2012-11-20 225 views
1

好的,這可能很簡單,但無論我申請多少咖啡,我的大腦都不會激活。ANTLR匹配日期範圍

我需要與ANTLR匹配以下模式:

5 YEARS 
5 YEARS 2 MONTHS 
5 YEARS 2 MONTHS 3 DAYS 
2 MONTHS 3 DAYS 
5 YEARS 3 DAYS 
etc 

於是,我開始了以下規則:

atom returns [Object value] 
    // start w/ a duration. Returned value will be a Joda Period object 
    : (INTEGER ('YEAR'|'YEARS'))? (INTEGER ('MONTH'|'MONTHS'))? (INTEGER ('DAY'|'DAYS')? 
    ; 

顯然是行不通的。我知道這很簡單,但我現在有一個主要的大腦404。

(一旦我得到了統治權,我就倒在詞法定義移動的定義)

更新: 以下規則集的作品,由於輸入先前提供的。再次感謝。

datePeriod returns [Object value] 
    : year month? week? day? EOF 
    { 
    $value = new Period($year.num, $month.num, $week.num, $day.num,0,0,0,0); 
    } 
    | month week? day? EOF 
    { 
    $value = new Period(0, $month.num, $week.num, $day.num,0,0,0,0); 
    } 
    | week day? EOF 
    { 
    $value = new Period(0,0, $week.num, $day.num,0,0,0,0); 
    } 
    | day EOF 
    { 
    $value = new Period(0, 0, 0, $day.num,0,0,0,0); 
    } 
    ; 

year returns [int num] 
    : INTEGER YEAR 
    { 
    $num = $INTEGER.int; 
    } 
    ; 

month returns [int num] 
    : INTEGER MONTH 
    { 
    $num = $INTEGER.int; 
    } 
    ; 

week returns [int num] 
    : INTEGER WEEK 
    { 
     $num = $INTEGER.int; 
    } 
    ; 

day returns [int num] 
    : INTEGER DAY 
    { 
    $num = $INTEGER.int; 
    } 
    ; 

YEAR: ('YEAR'|'YEARS'); 
MONTH: ('MONTH'|'MONTHS'); 
WEEK: ('WEEK'|'WEEKS'); 
DAY: ('DAY'|'DAYS'); 

不幸的是,我ANTLR想法正折騰出警告,如:

Decision can match input such as "INTEGER MONTH" using multiple alternatives: 1, 2 

傑森

+0

這是一個錯字,我固定它。事實是,它必須是0或1年/年,0或1個月/月,和/或0或1天/天。它必須至少有一個令牌,但可以有三個。 – Jason

回答

1

下面是一個簡單的語法如你所描述他們可以解析日期。請注意,換行字符不平凡/不會被忽略,因爲「4 yEARS \ n4 MONTHS」應該明確地解析爲兩個日期。

grammar dates; 

options { 
    language = Java; 
    output = AST; 
}      

parse 
    : '\n'* date ('\n'+ date)* '\n'* EOF 
    ; 

date 
    // start w/ a duration. Returned value will be a Joda Period object 
    : year month? day? 
    {System.out.println(String.format("\%dy \%dm \%dd", $year.num, $month.num, $day.num));} 
    | month day? 
    {System.out.println(String.format("0y \%dm \%dd", $month.num, $day.num));} 
    | day 
    {System.out.println(String.format("0y 0m \%dd", $day.num));} 
    ; 

year returns [int num] 
    : INTEGER YEAR 
     {$num = $INTEGER.int;} 
    ; 
month returns [int num] 
    : INTEGER MONTH 
     {$num = $INTEGER.int;} 
    ; 
day returns [int num] 
    : INTEGER DAY 
     {$num = $INTEGER.int;} 
    ; 
DAY : 'DAY' | 'DAYS' 
    ;  
MONTH 
    : 'MONTH' | 'MONTHS' 
    ;  
YEAR: 'YEAR' | 'YEARS' 
    ;  
INTEGER 
    : '0' 
    | ('1'..'9')('0'..'9')* 
    ; 
WS 
    : ('\t' | ' ' | '\r') {skip();} 
    ; 

測試輸入:

5 YEARS 
5 YEARS 2 MONTHS 
5 YEARS 2 MONTHS 3 DAYS 
2 MONTHS 3 DAYS 
5 YEARS 3 DAYS 
7 DAYS 
1 MONTH 

測試輸出:

5y 0m 0d 
5y 2m 0d 
5y 2m 3d 
0y 2m 3d 
5y 0m 3d 
0y 0m 7d 
0y 1m 0d 
+0

我可能在您的樣本日期列表中讀了太多內容,並認爲這些內容都在同一個流中。如果情況並非如此(即如果將日期作爲其他內容的一部分進行分析),那麼我對有關(和相關代碼的)新行的評論就無關緊要了。 – user1201210

+0

那些不是多個流,它們是單獨的測試用例,對不起。我查看了你的回覆並添加了你的建議,但我現在收到了幾條警告。我已經更新了這個問題。 – Jason

+0

沒關係。將EOF添加到每個規則的末尾使得警告消失。 – Jason