From 688169fd83b24564b653c03977c168cea50ccd35 Mon Sep 17 00:00:00 2001 From: matz Date: Thu, 23 Mar 2000 08:37:35 +0000 Subject: 2000-03-23 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@648 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/date2.rb | 15 +- lib/getopts.rb | 206 ++++++++--------- lib/parsedate.rb | 661 +++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 696 insertions(+), 186 deletions(-) (limited to 'lib') diff --git a/lib/date2.rb b/lib/date2.rb index ef8bf832c1..706fec744e 100644 --- a/lib/date2.rb +++ b/lib/date2.rb @@ -1,5 +1,5 @@ -# date2.rb: Written by Tadayoshi Funaba 1998, 1999 -# $Id: date2.rb,v 1.17 1999/09/15 05:34:07 tadf Exp $ +# date2.rb: Written by Tadayoshi Funaba 1998-2000 +# $Id: date2.rb,v 1.18 2000/03/20 16:23:32 tadf Exp $ class Date @@ -110,6 +110,10 @@ class Date def jd_to_mjd(jd) jd - 2400000.5 end def tjd_to_jd(tjd) tjd + 2440000.5 end def jd_to_tjd(jd) jd - 2440000.5 end + def tjd2_to_jd(cycle, tjd) tjd_to_jd(cycle * 10000 + tjd) end + def jd_to_tjd2(jd) clfloor(jd_to_tjd(jd), 10000) end + def ld_to_jd(ld) ld + 2299160 end + def jd_to_ld(jd) jd - 2299160 end def julian_leap? (y) y % 4 == 0 end def gregorian_leap? (y) y % 4 == 0 and y % 100 != 0 or y % 400 == 0 end @@ -213,15 +217,18 @@ class Date def rjd() @rjd end def rmjd() Date.jd_to_mjd(@rjd) end def rtjd() Date.jd_to_tjd(@rjd) end + def rtjd2() Date.jd_to_tjd2(@rjd) end - once :rmjd, :rtjd + once :rmjd, :rtjd, :rtjd2 def jd() Date.rjd_to_jd(@rjd)[0] end def fr1() Date.rjd_to_jd(@rjd)[1] end def mjd() Date.jd_to_mjd(jd) end def tjd() Date.jd_to_tjd(jd) end + def tjd2() Date.jd_to_tjd2(jd) end + def ld() Date.jd_to_ld(jd) end - once :jd, :fr1, :mjd, :tjd + once :jd, :fr1, :mjd, :tjd, :tjd2, :ld def civil() Date.jd_to_civil(jd, @sg) end def ordinal() Date.jd_to_ordinal(jd, @sg) end diff --git a/lib/getopts.rb b/lib/getopts.rb index b513f89f31..490523b878 100644 --- a/lib/getopts.rb +++ b/lib/getopts.rb @@ -1,141 +1,127 @@ # -# getopts.rb - -# $Release Version: $ -# $Revision$ -# $Date$ -# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) +# getopts.rb - +# $Release Version: $ +# $Revision$ +# $Date$ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- # this is obsolete; use getoptlong # +# 2000-03-21 +# modified by Minero Aoki # $RCS_ID=%q$Header$ -def isSingle(lopt) - if lopt.index(":") - if lopt.split(":")[0].length == 1 - return true - end - end - return nil -end -def getOptionName(lopt) - return lopt.split(":")[0] -end +def getopts( single_opts, *options ) + single_opts_exp = (single_opts && !single_opts.empty?) ? + /[#{single_opts}]/ : nil + single_colon_exp = nil + single_colon = nil + opt = arg = val = nil + boolopts = {} + valopts = {} + argv = ARGV + newargv = [] -def getDefaultOption(lopt) - od = lopt.split(":")[1] - if od - return od + # + # set default + # + if single_opts then + single_opts.each_byte do |byte| + boolopts[ byte.chr ] = false end - return nil end + unless options.empty? then + single_colon = '' -def setOption(name, value) - eval("$OPT_" + name + " = " + 'value') + options.each do |opt| + m = /\A([^:]+):(.*)\z/.match( opt ) + if m then + valopts[ m[1] ] = m[2].empty? ? 0 : m[2] + else + boolopts[ opt ] = false end - -def setDefaultOption(lopt) - d = getDefaultOption(lopt) - if d - setOption(getOptionName(lopt), d) end + valopts.each do |opt, dflt| + if opt.size == 1 then + single_colon << opt end - -def setNewArgv(newargv) - ARGV.clear - for na in newargv - ARGV << na end -end - -def getopts(single_opts, *options) - if options - single_colon = "" - long_opts = [] - sc = 0 - for o in options - setDefaultOption(o) - if isSingle(o) - single_colon[sc, 0] = getOptionName(o) - sc += 1 + if single_colon.empty? then + single_colon = single_colon_exp = nil else - long_opts.push(o) - end + single_colon_exp = /[#{single_colon}]/ end end - opts = {} - count = 0 - newargv = [] - while ARGV.length != 0 - compare = nil - case ARGV[0] - when /^--?$/ - ARGV.shift - newargv += ARGV + # + # scan + # + c = 0 + arg = argv.shift + while arg do + case arg + when /\A--?\z/ # xinit -- -bpp 24 + newargv.concat argv break - when /^--.*/ - compare = ARGV[0][2, (ARGV[0].length - 2)] - if long_opts != "" - for lo in long_opts - if lo.index(":") && getOptionName(lo) == compare - if ARGV.length <= 1 - return nil - end - setOption(compare, ARGV[1]) - opts[compare] = true - ARGV.shift - count += 1 - break - elsif lo == compare - setOption(compare, true) - opts[compare] = true - count += 1 - break - end - end - end - if compare.length <= 1 - return nil + + when /\A--(.*)/ + opt = $1 + if valopts.key? opt then # imclean --src +trash + return nil if argv.empty? + valopts[ opt ] = argv.shift + elsif boolopts.key? opt then # ruby --verbose + boolopts[ opt ] = true + else + return nil + end + c += 1 + + when /\A-(.+)/ + arg = $1 + 0.upto( arg.size - 1 ) do |idx| + opt = arg[idx, 1] + if single_opts and single_opts_exp === opt then + boolopts[ opt ] = true # ruby -h + c += 1 + + elsif single_colon and single_colon_exp === opt then + val = arg[ (idx+1)..-1 ] + if val.empty? then # ruby -e 'p $:' + return nil if argv.empty? + valopts[ opt ] = argv.shift + else # cc -ohello ... + valopts[ opt ] = val end - when /^-.*/ - for idx in 1..(ARGV[0].length - 1) - compare = ARGV[0][idx, 1] - if single_opts && compare =~ "[" + single_opts + "]" - setOption(compare, true) - opts[compare] = true - count += 1 - elsif single_colon != "" && compare =~ "[" + single_colon + "]" - if ARGV[0][idx..-1].length > 1 - setOption(compare, ARGV[0][(idx + 1)..-1]) - opts[compare] = true - count += 1 - elsif ARGV.length <= 1 - return nil - else - setOption(compare, ARGV[1]) - opts[compare] = true - ARGV.shift - count += 1 - end - break - end + c += 1 + + break + else + return nil + end + end + + else # ruby test.rb + newargv.push arg end - else - compare = ARGV[0] - opts[compare] = true - newargv << ARGV[0] + + arg = argv.shift end - ARGV.shift - if !opts.has_key?(compare) - return nil + # + # set + # + boolopts.each do |opt, val| + eval "$OPT_#{opt} = val" end + valopts.each do |opt, val| + eval "$OPT_#{opt} = #{val == 0 ? 'nil' : 'val'}" end - setNewArgv(newargv) - return count + argv.replace newargv + + c end diff --git a/lib/parsedate.rb b/lib/parsedate.rb index 35fffcfe98..59a8b4f3b4 100644 --- a/lib/parsedate.rb +++ b/lib/parsedate.rb @@ -1,78 +1,590 @@ -module ParseDate +# parsedate2.ry: Written by Tadayoshi Funaba 1999, 2000 +# $Id: parsedate2.ry,v 1.5 2000/03/20 16:23:46 tadf Exp $ +## Generated by rbison version 0.0.5. + +class ParseDatePar + + class ParseError < StandardError ; end + class LexError < StandardError ; end + NULL = nil + + attr :yydebug, true + + DAY = 257 + DIGITS = 258 + MON = 259 + LETTERS = 260 + MERID = 261 + + ## Parser declarations begin + ## Parser declarations end + + YYFINAL = 84 + YYFLAG = -32768 + YYNTBASE = 14 + YYTRANSLATE = [ 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 13, 8, 9, 10, 11, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 12, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, + 7 + ] + YYPRHS = [ 0, + 0, 1, 3, 6, 8, 12, 14, 20, 26, 32, + 34, 38, 40, 44, 45, 48, 50, 51, 53, 55, + 57, 60, 63, 65, 67, 69, 71, 73, 80, 88, + 94, 98, 104, 108, 115, 116, 119, 122, 123, 125, + 128, 129, 131, 132, 134, 136, 139, 142, 147, 149 + ] + YYRHS = [ -1, + 17, 0, 16, 15, 0, 19, 0, 19, 18, 22, + 0, 28, 0, 28, 18, 19, 18, 22, 0, 19, + 18, 28, 18, 22, 0, 19, 18, 22, 18, 28, + 0, 23, 0, 23, 18, 28, 0, 30, 0, 30, + 18, 32, 0, 0, 17, 18, 0, 3, 0, 0, + 8, 0, 20, 0, 21, 0, 4, 5, 0, 5, + 4, 0, 4, 0, 24, 0, 25, 0, 26, 0, + 27, 0, 4, 9, 4, 9, 4, 31, 0, 6, + 4, 10, 4, 10, 4, 31, 0, 4, 9, 5, + 9, 4, 0, 4, 11, 4, 0, 4, 11, 4, + 11, 4, 0, 4, 7, 34, 0, 4, 12, 4, + 29, 33, 34, 0, 0, 12, 4, 0, 4, 31, + 0, 0, 6, 0, 4, 34, 0, 0, 7, 0, + 0, 35, 0, 6, 0, 6, 6, 0, 36, 4, + 0, 36, 4, 12, 4, 0, 9, 0, 13, 0 + ] + YYRLINE = [ 0, + 14, 14, 14, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 28, 28, 30, 32, 32, 34, 34, + 36, 38, 40, 42, 42, 42, 42, 44, 58, 72, + 86, 91, 105, 109, 116, 116, 118, 141, 141, 143, + 156, 156, 158, 158, 160, 161, 166, 167, 170, 170 + ] + YYTNAME = [ "$","error","$undefined.","DAY","DIGITS", +"MON","LETTERS","MERID","','","'-'","'.'","'/'","':'","'+'","repr","dat","odaycom", +"day","ocom","woy","eu","us","year","wy","iso","jis","vms","sla","time","osec", +"ddd","otee","ttt","omerid","ozone","zone","sign", NULL + ] + YYR1 = [ 0, + 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 16, 16, 17, 18, 18, 19, 19, + 20, 21, 22, 23, 23, 23, 23, 24, 25, 26, + 27, 27, 28, 28, 29, 29, 30, 31, 31, 32, + 33, 33, 34, 34, 35, 35, 35, 35, 36, 36 + ] + YYR2 = [ 0, + 0, 1, 2, 1, 3, 1, 5, 5, 5, 1, + 3, 1, 3, 0, 2, 1, 0, 1, 1, 1, + 2, 2, 1, 1, 1, 1, 1, 6, 7, 5, + 3, 5, 3, 6, 0, 2, 2, 0, 1, 2, + 0, 1, 0, 1, 1, 2, 2, 4, 1, 1 + ] + YYDEFACT = [ 14, + 16, 0, 17, 38, 0, 0, 3, 4, 19, 20, + 10, 24, 25, 26, 27, 17, 12, 18, 15, 21, + 39, 43, 0, 0, 0, 37, 22, 0, 0, 0, + 0, 0, 45, 49, 50, 33, 44, 0, 0, 0, + 31, 35, 0, 23, 5, 17, 0, 11, 0, 17, + 43, 13, 46, 47, 0, 0, 0, 0, 41, 0, + 0, 0, 0, 40, 0, 38, 30, 32, 36, 42, + 43, 0, 9, 23, 8, 7, 48, 28, 34, 38, + 29, 0, 0, 0 + ] + YYDEFGOTO = [ 82, + 7, 2, 3, 19, 8, 9, 10, 45, 11, 12, + 13, 14, 15, 16, 59, 17, 26, 52, 71, 36, + 37, 38 + ] + YYPACT = [ 10, +-32768, 30, 6, 11, 37, 39,-32768, 23,-32768,-32768, + 23,-32768,-32768,-32768,-32768, 7, 23,-32768,-32768,-32768, +-32768, 19, 25, 40, 41,-32768,-32768, 36, 43, 44, + 35, 45, 46,-32768,-32768,-32768,-32768, 47, 48, 49, + 42, 38, 50, 14, 23, 51, 14,-32768, 55, 51, + 19,-32768,-32768, 52, 57, 58, 59, 61, 60, 56, + 44, 64, 64,-32768, 65, 66,-32768,-32768,-32768,-32768, + 19, 67,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 66, +-32768, 70, 73,-32768 + ] + YYPGOTO = [ -32768, +-32768,-32768,-32768, -8, 24,-32768,-32768, -51,-32768,-32768, +-32768,-32768,-32768, -28,-32768,-32768, -61,-32768,-32768, -47, +-32768,-32768 + ] + YYLAST = 73 + YYTABLE = [ 29, + 46, 48, 30, 64, 78, -2, -6, 31, 32, -1, + 75, 76, 1, 18, 18, 20, 21, 22, 81, 23, + 22, 24, 25, 79, 33, 25, -17, 34, 39, 40, + 18, 35, 73, 4, 5, 6, 61, 62, 49, 5, + 27, 63, 28, 41, 42, 43, 44, 47, 51, 58, + 54, 53, 57, 60, 50, 0, 55, 56, 18, 20, + 66, 67, 68, 65, 69, 72, 70, 74, 77, 83, + 80, 21, 84 + ] + YYCHECK = [ 8, + 29, 30, 11, 51, 66, 0, 0, 16, 17, 0, + 62, 63, 3, 8, 8, 5, 6, 7, 80, 9, + 7, 11, 12, 71, 6, 12, 4, 9, 4, 5, + 8, 13, 61, 4, 5, 6, 45, 46, 4, 5, + 4, 50, 4, 4, 4, 10, 4, 4, 4, 12, + 4, 6, 11, 4, 31, -1, 9, 9, 8, 5, + 4, 4, 4, 12, 4, 10, 7, 4, 4, 0, + 4, 6, 0 + ] + YYEMPTY = -2 + YYEOF = 0 + YYTERROR = 1 + + def initialize + @yydebug = false + end + + def yyparse(lexer) + yyerrstatus = 0 + yychar = YYEMPTY + yystate = 0 + yyss = [] + yyvs = ["nil"] + yyval = 0 + jump = :YYNEWSTATE + + while true + + case jump + + when :YYNEWSTATE + if @yydebug + printf($stderr, "Entering state %d\n", yystate) + end + yyss.push(yystate) + jump = :YYBACKUP + next + + when :YYBACKUP + yyn = YYPACT[yystate] + if yyn == YYFLAG + jump = :YYDEFAULT + next + end + + ## get a lookahead token if we don't already have one + if yychar == YYEMPTY + if @yydebug + printf($stderr, "Reading a token: ") + end + begin + yychar, yylval = lexer.yylex + rescue LexError + raise ParseError, "lex error" + end + end + + ## if lookahead <= 0, end of input + if yychar <= 0 + yychar1 = 0 + yychar = YYEOF + if @yydebug + printf($stderr, "Now at end of input.\n") + end + else + yychar1 = yychar < 0 || yychar > 261 ? 37 : YYTRANSLATE[yychar] + if @yydebug + printf($stderr, "Next token is %d (%s,%s)\n", yychar, + YYTNAME[yychar1], yylval) + end + end + + ## see if we know what to do with this token in this state + yyn += yychar1 + if yyn < 0 || yyn > YYLAST || YYCHECK[yyn] != yychar1 + jump = :YYDEFAULT + next + end + + ## yyn is what to do for this token type in this state + ## negative -> reduce, - yyn is the rule number + ## positive -> shift, yyn is the new state + ## New state is final state, don't bother to shift, just + ## return success + ## 0, or most negative number -> error + yyn = YYTABLE[yyn] + if yyn < 0 + if yyn == YYFLAG + jump = :YYERRLAB + next + end + yyn = - yyn + jump = :YYREDUCE + next + elsif yyn == 0 + jump = :YYERRLAB + next + end + + if yyn == YYFINAL + return ## accept + end + + ## shift the lookahead token + if @yydebug + printf($stderr, "Shifting token %d (%s), ", yychar, + YYTNAME[yychar1]) + end + + ## discard the token being shifted unless it is eof + if yychar != YYEOF + yychar = YYEMPTY + end + yyvs.push(yylval) + + ## count tokens shifted since error; after, three turn off + ## error status + yyerrstatus -= 1 if yyerrstatus > 0 + + yystate = yyn + jump = :YYNEWSTATE + next + + when :YYDEFAULT + yyn = YYDEFACT[yystate] + if yyn == 0 + jump = :YYERRLAB + next + else + jump = :YYREDUCE + next + end + + ## do a reduction. yyn is the number of the rule to reduce with + when :YYREDUCE + yylen = YYR2[yyn] + if yylen > 0 + yyval = yyvs[yyvs.size - yylen] + end + + if @yydebug + printf($stderr, "Reducing via rule %d (line %d), ", yyn, + YYRLINE[yyn]) + i = YYPRHS[yyn] + while YYRHS[i] > 0 + printf($stderr, "%s ", YYTNAME[YYRHS[i]]) + i += 1 + end + printf($stderr, " -> %s\n", YYTNAME[YYR1[yyn]]) + end + + case yyn + when 16 + store(:wday, yyvs[-1].to_i) + when 21 + store(:mday, yyvs[-2].to_i); store(:mon, yyvs[-1]) + when 22 + store(:mon, yyvs[-2]); store(:mday, yyvs[-1].to_i) + when 23 + store(:year, yyvs[-1].to_i) + when 28 + + if yyvs[-1 + -1].size >= 4 + store(:mday, yyvs[-1 + -5].to_i) + store(:mon, yyvs[-1 + -3].to_i) + store(:year, yyvs[-1 + -1].to_i) + else + store(:year, yyvs[-1 + -5].to_i) + store(:mon, yyvs[-1 + -3].to_i) + store(:mday, yyvs[-1 + -1].to_i) + end + + when 29 + + e = { 'M'=>1867, + 'T'=>1911, + 'S'=>1925, + 'H'=>1988 + }[yyvs[-1 + -6]] + raise ParseError, 'YYERROR' unless e + store(:year, yyvs[-1 + -5].to_i + e) + store(:mon, yyvs[-1 + -3].to_i) + store(:mday, yyvs[-1 + -1].to_i) + + when 30 + + if yyvs[-1 + -4].size >= 4 + store(:year, yyvs[-1 + -4].to_i) + store(:mon, yyvs[-1 + -2]) + store(:mday, yyvs[-1 + 0].to_i) + else + store(:mday, yyvs[-1 + -4].to_i) + store(:mon, yyvs[-1 + -2]) + store(:year, yyvs[-1 + 0].to_i) + end + + when 31 + + store(:mon, yyvs[-1 + -2].to_i) + store(:mday, yyvs[-1 + 0].to_i) + + when 32 + + if yyvs[-1 + -4].size >= 4 + store(:year, yyvs[-1 + -4].to_i) + store(:mon, yyvs[-1 + -2].to_i) + store(:mday, yyvs[-1 + 0].to_i) + else + store(:mon, yyvs[-1 + -4].to_i) + store(:mday, yyvs[-1 + -2].to_i) + store(:year, yyvs[-1 + 0].to_i) + end + + when 33 + + store(:hour, yyvs[-1 + -2].to_i + yyvs[-1 + -1]) + + when 34 + + store(:hour, yyvs[-1 + -5].to_i + yyvs[-1 + -1]) + store(:min, yyvs[-1 + -3].to_i) + + when 36 + store(:sec, yyvs[-1].to_i) + when 37 + + case yyvs[-1 + -1].size + when 4 + store(:mon, yyvs[-1 + -1][ 0, 2].to_i) + store(:mday, yyvs[-1 + -1][ 2, 2].to_i) + when 6 + store(:year, yyvs[-1 + -1][ 0, 2].to_i) + store(:mon, yyvs[-1 + -1][ 2, 2].to_i) + store(:mday, yyvs[-1 + -1][ 4, 2].to_i) + when 8, 10, 12, 14 + store(:year, yyvs[-1 + -1][ 0, 4].to_i) + store(:mon, yyvs[-1 + -1][ 4, 2].to_i) + store(:mday, yyvs[-1 + -1][ 6, 2].to_i) + store(:hour, yyvs[-1 + -1][ 8, 2].to_i) if yyvs[-1 + -1].size >= 10 + store(:min, yyvs[-1 + -1][10, 2].to_i) if yyvs[-1 + -1].size >= 12 + store(:sec, yyvs[-1 + -1][12, 2].to_i) if yyvs[-1 + -1].size >= 14 + else + raise ParseError, 'YYERROR' + end + + when 39 + raise ParseError, 'YYERROR' unless yyvs[-1] == 'T' + when 40 + + case yyvs[-1 + -1].size + when 2, 4, 6 + store(:hour, yyvs[-1 + -1][ 0, 2].to_i) + store(:min, yyvs[-1 + -1][ 2, 2].to_i) if yyvs[-1 + -1].size >= 4 + store(:sec, yyvs[-1 + -1][ 4, 2].to_i) if yyvs[-1 + -1].size >= 6 + else + raise ParseError, 'YYERROR' + end + + when 41 + yyval = 0 + when 45 + store(:zone, yyvs[-1]) + when 46 + + raise ParseError, 'YYERROR' unless yyvs[-1 + 0] == 'DST' + store(:zone, yyvs[-1 + -1] + ' ' + yyvs[-1 + 0]) + + when 47 + store(:zone, yyvs[-2] + yyvs[-1]) + when 48 + store(:zone, yyvs[-4] + yyvs[-3] + yyvs[-2] + yyvs[-1]) + when -65536 ## never used, placeholder for ruby + end + + if yylen > 0 + yyss[(yyss.size - yylen) .. (yyss.size - 1)] = [] + yyvs[(yyvs.size - yylen) .. (yyvs.size - 1)] = [] + end + + yyvs.push(yyval) + + if @yydebug + printf($stderr, "State stack now: %s\n", yyss.join(' ')) + printf($stderr, "Value stack now: %s\n", yyvs.join(' ')) + end + + ## "Shift" the result of the reduction. + yyn = YYR1[yyn] + yystate = YYPGOTO[yyn - YYNTBASE] + yyss[-1] + if yystate >=0 && yystate <= YYLAST && + YYCHECK[yystate] == yyss[-1] + yystate = YYTABLE[yystate] + else + yystate = YYDEFGOTO[yyn - YYNTBASE] + end + jump = :YYNEWSTATE + next + + when :YYERRLAB + if yyerrstatus == 0 && @yydebug + printf($stderr, "Parse error!\n") + end + jump = :YYERRLAB1 + next + + when :YYERRLAB1 + if yyerrstatus == 3 + if yychar == YYEOF + raise ParseError, "parse error" + end + if @yydebug + printf($stderr, "Discarding token %d (%s).\n", yychar, + YYTNAME[yychar1]) + end + yychar = YYEMPTY + end + + yyerrstatus = 3 + jump = :YYERRHANDLE + next + + when :YYERRPOP + if yyvs.empty? + raise ParseError, "parse error" + end + ## don't pop if the state on top of the stack can handle + ## the error token + yystate = yyss[-1] + if YYCHECK[YYPACT[yystate] + YYTERROR] != YYTERROR + yyvs.pop + yyss.pop + if @yydebug + printf($stderr, "Error: state stack now: %s\n", + yyss.join(' ')) + printf($stderr, "Error: Value stack now: %s\n", + yyvs.join(' ')) + end + end + jump = :YYERRHANDLE + next + + when :YYERRHANDLE + yyn = YYPACT[yystate] + if yyn == YYFLAG + jump = :YYERRPOP + next + end + + yyn += YYTERROR + if yyn < 0 || yyn > YYLAST || YYCHECK[yyn] != YYTERROR + jump = :YYERRPOP + next + end + + yyn = YYTABLE[yyn] + if yyn < 0 + if yyn == YYFLAG + jump = :YYERRPOP + next + end + yyn = -yyn + jump = :YYREDUCE + next + elsif yyn == 0 + jump = :YYERRPOP + next + end + + if yyn == YYFINAL + return ## accept + end + + if @yydebug + printf($stderr, "Shifting error token, ") + end + + yyvs.push(yylval) + yystate = yyn + jump = :YYNEWSTATE + next + + end ## case + + end ## while true + + end ## yyparse + +end ## class + +## Additional user code +class ParseDateLex MONTHS = { 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8, - 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 } - MONTHPAT = MONTHS.keys.join('|') + 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 + } + MONTHPAT = MONTHS.keys.sort.reverse.join('|') DAYS = { 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, - 'thu' => 4, 'fri' => 5, 'sat' => 6 } - DAYPAT = DAYS.keys.join('|') - - def parsedate(date, guess=false) - # part of ISO 8601 - # yyyy-mm-dd | yyyy-mm | yyyy - # date hh:mm:ss | date Thh:mm:ss - if date =~ /^(\d\d\d\d)-?(?:(\d\d)-?(\d\d)?)? *T?(?:(\d\d):?(\d\d):?(\d\d)?)?$/ - return $1.to_i, - if $2 then $2.to_i else 1 end, - if $3 then $3.to_i else 1 end, - if $4 then $4.to_i end, - if $5 then $5.to_i end, - if $6 then $6.to_i end, - nil, - nil + 'thu' => 4, 'fri' => 5, 'sat' => 6 + } + DAYPAT = DAYS.keys.sort.reverse.join('|') + def initialize(str) @str = str end + def reset(str) @str = str end + def yylex + @str = @str.sub(/\A\s+/, '') + return [-1, nil] if @str.size == 0 + if /\A(#{DAYPAT})[a-z]*\.?/i =~ @str + @str = $' + return [ParseDatePar::DAY, DAYS[$1[0, 3].downcase]] end - date = date.dup - if date.sub!(/(#{DAYPAT})[a-z]*,?/i, ' ') - wday = DAYS[$1.downcase] + if /\A(\d+)(?:(?:th|st|nd|rd)\b)?/ =~ @str + @str = $' + return [ParseDatePar::DIGITS, $1] end - if date.sub!(/(\d+):(\d+)(?::(\d+))?(?:\s*(am|pm))?(?:\s+([a-z]{1,4}(?:\s+[a-z]{1,4}|[-+]\d{4})?|[-+]\d{4}))?/i, ' ') - hour = $1.to_i - min = $2.to_i - if $3 - sec = $3.to_i - end - if $4 == 'pm' - hour += 12 - end - if $5 - zone = $5 - end + if /\A(#{MONTHPAT})[a-z]*\.?/i =~ @str + @str = $' + return [ParseDatePar::MON, MONTHS[$1[0, 3].downcase]] end - if date.sub!(/(\d+)\S*\s+(#{MONTHPAT})\S*(?:\s+(\d+))?/i, ' ') - mday = $1.to_i - mon = MONTHS[$2.downcase] - if $3 - year = $3.to_i - end - elsif date.sub!(/(#{MONTHPAT})\S*\s+(\d+)\S*,?(?:\s+(\d+))?/i, ' ') - mon = MONTHS[$1.downcase] - mday = $2.to_i - if $3 - year = $3.to_i - end - elsif date.sub!(/(\d+)\/(\d+)(?:\/(\d+))/, ' ') - mon = $1.to_i - mday = $2.to_i - if $3 - year = $3.to_i - end - elsif date.sub!(/(\d+)-(#{MONTHPAT})-(\d+)/i, ' ') - mday = $1.to_i - mon = MONTHS[$2.downcase] - year = $3.to_i - elsif date.sub!(/(\d+)-(#{MONTHPAT})-(\d+)/i, ' ') - mday = $1.to_i - mon = MONTHS[$2.downcase] - year = $3.to_i + if /\A([ap]\.?m\.?\b)/i =~ @str + @str = $' + return [ParseDatePar::MERID, + if $1[0, 1].downcase == 'a' then 0 else 12 end] + end + if /\A([a-z]+)/i =~ @str + @str = $' + return [ParseDatePar::LETTERS, $1] end - if date.sub!(/\d{4}/i, ' ') - year = $&.to_i - elsif date.sub!(/\d\d/i, ' ') - year = $&.to_i + if /\A(.)/ =~ @str + @str = $' + return [$1[0], $1] end - if guess and year + end +end +class ParseDatePar + def clear() @values = {} end + def store(key, val) @values[key] = val end + def values(cyear) + year = @values[:year] + if cyear and year if year < 100 if year >= 69 year += 1900 @@ -81,13 +593,18 @@ module ParseDate end end end - return year, mon, mday, hour, min, sec, zone, wday + @values[:year] = year + @values.indexes(:year, :mon, :mday, + :hour, :min, :sec, :zone, :wday) end - - module_function :parsedate end - -if __FILE__ == $0 - p Time.now.asctime - p ParseDate.parsedate(Time.now.asctime) +module ParseDate + def parsedate(date, cyear=false) + lex = ParseDateLex.new(date) + par = ParseDatePar.new + par.clear + begin par.yyparse(lex); rescue; end + par.values(cyear) + end + module_function :parsedate end -- cgit v1.2.3