blob: 44cb416d72f1c0e882df4981b17ac3b972656897 [file] [log] [blame]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
/**
* RFC2822 date parser.
*
* Created 9/28/2004
* by Joe Cheng <code@joecheng.com>
*/
options {
STATIC=false;
LOOKAHEAD=1;
JDK_VERSION = "1.5";
OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";
//DEBUG_PARSER=true;
//DEBUG_TOKEN_MANAGER=true;
}
PARSER_BEGIN(DateTimeParser)
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.mime4j.field.datetime.parser;
import org.apache.james.mime4j.field.datetime.DateTime;
public class DateTimeParser {
private static final boolean ignoreMilitaryZoneOffset = true;
public static void main(String args[]) throws ParseException {
while (true) {
try {
DateTimeParser parser = new DateTimeParser(System.in);
parser.parseLine();
} catch (Exception x) {
x.printStackTrace();
return;
}
}
}
private static int parseDigits(Token token) {
return Integer.parseInt(token.image, 10);
}
private static int getMilitaryZoneOffset(char c) {
if (ignoreMilitaryZoneOffset)
return 0;
c = Character.toUpperCase(c);
switch (c) {
case 'A': return 1;
case 'B': return 2;
case 'C': return 3;
case 'D': return 4;
case 'E': return 5;
case 'F': return 6;
case 'G': return 7;
case 'H': return 8;
case 'I': return 9;
case 'K': return 10;
case 'L': return 11;
case 'M': return 12;
case 'N': return -1;
case 'O': return -2;
case 'P': return -3;
case 'Q': return -4;
case 'R': return -5;
case 'S': return -6;
case 'T': return -7;
case 'U': return -8;
case 'V': return -9;
case 'W': return -10;
case 'X': return -11;
case 'Y': return -12;
case 'Z': return 0;
default: return 0;
}
}
private static class Time {
private int hour;
private int minute;
private int second;
private int zone;
public Time(int hour, int minute, int second, int zone) {
this.hour = hour;
this.minute = minute;
this.second = second;
this.zone = zone;
}
public int getHour() { return hour; }
public int getMinute() { return minute; }
public int getSecond() { return second; }
public int getZone() { return zone; }
}
private static class Date {
private String year;
private int month;
private int day;
public Date(String year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public String getYear() { return year; }
public int getMonth() { return month; }
public int getDay() { return day; }
}
}
PARSER_END(DateTimeParser)
DateTime parseLine() :
{DateTime dt;}
{
dt=date_time() ["\r"] "\n"
{ return dt; }
}
DateTime parseAll() :
{DateTime dt;}
{
dt=date_time() <EOF>
{ return dt; }
}
DateTime date_time() :
{Date d; Time t;}
{
[ day_of_week() "," ]
d=date()
t=time()
{
return new DateTime(
d.getYear(),
d.getMonth(),
d.getDay(),
t.getHour(),
t.getMinute(),
t.getSecond(),
t.getZone()); // time zone offset
}
}
String day_of_week() :
{}
{
( "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
)
{ return token.image; }
}
Date date() :
{int d, m; String y;}
{
d=day() m=month() y=year()
{ return new Date(y, m, d); }
}
int day() :
{Token t;}
{
t=<DIGITS> { return parseDigits(t); }
}
int month() :
{}
{
"Jan" { return 1; }
| "Feb" { return 2; }
| "Mar" { return 3; }
| "Apr" { return 4; }
| "May" { return 5; }
| "Jun" { return 6; }
| "Jul" { return 7; }
| "Aug" { return 8; }
| "Sep" { return 9; }
| "Oct" { return 10; }
| "Nov" { return 11; }
| "Dec" { return 12; }
}
String year() :
{Token t;}
{
t=<DIGITS> { return t.image; }
}
Time time() :
{int h, m, s=0, z;}
{
h=hour() ":" m=minute() [ ":" s=second() ] z=zone()
{ return new Time(h, m, s, z); }
}
int hour() :
{Token t;}
{
t=<DIGITS> { return parseDigits(t); }
}
int minute() :
{Token t;}
{
t=<DIGITS> { return parseDigits(t); }
}
int second() :
{Token t;}
{
t=<DIGITS> { return parseDigits(t); }
}
int zone() :
{ Token t, u; int z; }
{
( t=< OFFSETDIR: ["+", "-"] > u=<DIGITS> { z=parseDigits(u)*(t.image.equals("-") ? -1 : 1); }
| z=obs_zone()
)
{ return z; }
}
int obs_zone() :
{Token t; int z;}
{
( "UT" { z=0; }
| "GMT" { z=0; }
| "EST" { z=-5; }
| "EDT" { z=-4; }
| "CST" { z=-6; }
| "CDT" { z=-5; }
| "MST" { z=-7; }
| "MDT" { z=-6; }
| "PST" { z=-8; }
| "PDT" { z=-7; }
| t=< MILITARY_ZONE: ["A"-"I","a"-"i","K"-"Z","k"-"z"] > { z=getMilitaryZoneOffset(t.image.charAt(0)); }
)
{ return z * 100; }
}
SPECIAL_TOKEN :
{
< WS: ( [" ", "\t"] )+ >
}
TOKEN_MGR_DECLS :
{
// Keeps track of how many levels of comment nesting
// we've encountered. This is only used when the 2nd
// level is reached, for example ((this)), not (this).
// This is because the outermost level must be treated
// specially anyway, because the outermost ")" has a
// different token type than inner ")" instances.
static int commentNest;
}
MORE :
{
// starts a comment
"(" : INCOMMENT
}
<INCOMMENT>
SKIP :
{
// ends a comment
< COMMENT: ")" > : DEFAULT
// if this is ever changed to not be a SKIP, need
// to make sure matchedToken.token = token.toString()
// is called.
}
<INCOMMENT>
MORE :
{
< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
| "(" { commentNest = 1; } : NESTED_COMMENT
| < <ANY>>
}
<NESTED_COMMENT>
MORE :
{
< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
| "(" { ++commentNest; }
| ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }
| < <ANY>>
}
TOKEN :
{
< DIGITS: ( ["0"-"9"] )+ >
}
// GLOBALS
<*>
TOKEN :
{
< #QUOTEDPAIR: "\\" <ANY> >
| < #ANY: ~[] >
}