HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Expressing Rebol Dates in EBNF

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
ebnfexpressingreboldates

Problem

I'm looking to define the Rebol date format in EBNF notation. I'd like as best as possible to only define valid dates—at least those that are valid in Rebol at the moment:

```
Date ::= DateDate ('/' Time DateZone?)?

DateDate ::=
DateDay31 ('-' DateMonth31 '-' | '/' DateMonth31 '/') DateYear
| DateDay30 ('-' DateMonth30 '-' | '/' DateMonth30 '/') DateYear
| DateDay28 ('-' DateMonthFebruary '-' | '/' DateMonthFebruary '/') DateYear
| "29" ('-' DateMonthFebruary '-' | '/' DateMonthFebruary '/') DateYearLeap
| DateYear ('-' DateMonth31 '-' | '/' DateMonth31 '/') DateDay31
| DateYear ('-' DateMonth30 '-' | '/' DateMonth30 '/') DateDay30
| DateYearLeap ('-' DateMonthFebruary '-' | '/' DateMonthFebruary '/') DateDay29
| DateYear ('-' DateMonthFebruary '-' | '/' DateMonthFebruary '/') DateDay28

/*
Currently years cannot be negative and have a maximum value of 16383
So the following two values are shortcuts.
*/
DateYear ::= Digit (Digit (Digit (Digit Digit?)?)?)?

DateYearLeap ::=
'1' Digit Digit DateYearLeapEnd
| Digit Digit DateYearLeapEnd
| Digit DateYearLeapEnd
| DateYearLeapEnd
| [048]

DateYearLeapEnd ::= [02468] [048] | [13579] [26]

DateMonth ::= DateMonth31 | DateMonth30 | DateMonthFebruary

DateDay31 ::= '3' [01] | DateDay29

DateDay30 ::= '30' | DateDay29

DateDay29 ::= [12] Digit | '0'? [1-9]

DateDay28 ::= '2' [0-8] | '1' Digit | '0'? [1-9]

DateMonth31 ::=
DateMonthJanuary |
DateMonthMarch |
DateMonthMay |
DateMonthJuly |
DateMonthAugust |
DateMonthOctober |
DateMonthDecember

DateMonth30 ::=
DateMonthApril |
DateMonthJune |
DateMonthSeptember |
DateMonthNovember

/ Currently only English month names are valid /
DateMonthJanuary ::= 'Jan' ('u' ('a' ('r' 'y'?)?)?)? | '0'? '1'

DateMonthFebruary ::= 'Feb' ('r' ('u' ('a' ('r' 'y'?)?)?)?)? | '0'? '2'

DateMonthMarch ::= 'Mar' ('c' 'h'?)? | '0'? '3'

DateMonthApril ::= 'Apr' ('i' 'l'?)? | '0'? '4'

Date

Solution

Is Janua really a valid month? If so, then you're fine, but I have a feeling that this would be more appropriate.

DateMonthJanuary ::= 'January' | 'Jan' | '0'? '1'


Which brings me to my next problem. It's case sensitive, right? So, 22-JAN-2015 wouldn't match. I believe it should, but I'm not familiar with Robol. Please correct me if I'm wrong.

I've seen this handled by defining case insensitive tokens for each letter.

A ::= 'a' | 'A'


And then define your rules from those tokens like this.

DateMonthJanuary ::= J A N U A R Y | J A N | '0'? '1'


My syntax may be a little off, I'm accustomed to ANTLR's flavor of EBNF, but that should illustrate the idea.

DateYearLeap ::=


I'm really not sure that I would handle that in your grammar. The logic is convoluted (not yours, just leap years in general) and I'm pretty sure this will match a few leap years that aren't. Much better for this one to be validated by your parser if that's possible.

/* Need to constrain to valid hours */
TimeHour ::= Sign Digit* | Sign? Digit+

/* Need to constrain to 0-59 */
TimeMinute ::= Sign? Digit Digit?

/* Need to constrain to 0-59.999999 */
TimeSecond ::= Sign? ((Digit Digit?)? '.' Digit+ | Digit Digit? '.'?)


I think you should be able to define tokens for these. It may take a bit of doing to get the precedence right, but start with something like this.

TimeMinute ::= Sign? [0-6] Digit
/* Optional Sign, Optional 10s Digit 0-6, 0-9*/

Code Snippets

DateMonthJanuary ::= 'January' | 'Jan' | '0'? '1'
A ::= 'a' | 'A'
DateMonthJanuary ::= J A N U A R Y | J A N | '0'? '1'
DateYearLeap ::=
/* Need to constrain to valid hours */
TimeHour ::= Sign Digit* | Sign? Digit+

/* Need to constrain to 0-59 */
TimeMinute ::= Sign? Digit Digit?

/* Need to constrain to 0-59.999999 */
TimeSecond ::= Sign? ((Digit Digit?)? '.' Digit+ | Digit Digit? '.'?)

Context

StackExchange Code Review Q#87696, answer score: 4

Revisions (0)

No revisions yet.