# 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.sort.reverse.join('|') DAYS = { 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, '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 if /\A(\d+)(?:(?:th|st|nd|rd)\b)?/ =~ @str @str = $' return [ParseDatePar::DIGITS, $1] end if /\A(#{MONTHPAT})[a-z]*\.?/i =~ @str @str = $' return [ParseDatePar::MON, MONTHS[$1[0, 3].downcase]] end 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 /\A(.)/ =~ @str @str = $' return [$1[0], $1] end 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 else year += 2000 end end end @values[:year] = year @values.indexes(:year, :mon, :mday, :hour, :min, :sec, :zone, :wday) end end 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