Mercurial > ~dholland > hg > ag > index.cgi
diff tests/agcl/parsifal/date_p1.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/agcl/parsifal/date_p1.syn Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,246 @@ +{/* + Date Translator + Copyright (c) 1995-1999, Parsifal Software + All Rights Reserved + See the file COPYING for license and usage terms. + + This program illustrates the use of AnaGram to translate a number of + different representations of data into a common format. The example + used shows how to translate any of a number of standard formats for + entering a date into a single format for further processing. + + The parser illustrated here recognizes six basic date formats, and + for each, will supply the current year if the year is not given. If + months are entered by name, they may be spelled out in full, or + abbreviated in the customary manner. Text may be upper or lower case. + Spaces or tabs may be used freely between the elements of the dates. + Some examples of the six formats, as applied to the date June 26, + 1999, are as follows: + + June 26 jun 26 June 26, 1999 JUN 26, 99 jun26,1999 + 26 June 26 jun 26 June 1999 26 JUN 99 26jun99 + 26-June 26-Jun 26-June-99 26-JUN-1999 + 6/26 6/26/99 6/26/1999 + 6-26 6-26-99 6-26-1999 + 6.26 6.26.99 6-26.1999 + 6/26/'99 6-26-'99 6.26.'99 + 6/26 '99 6-26 '99 6.26 '99 + 26/6 26/6/99 26/6/1999 + 26-6 26-6-99 26-6-1999 + 26.6 26.6.99 26.6.1999 + 26/6 '99 26-6 '99 26.6 '99 + 26 vi 26 vi 99 26 vi 1999 26 VI 99 26VI99 + 26 vi '99 + + If CHKDATE encounters a date of the form 2/3/99, it interrogates a + switch to determine whether to interpret this in the European manner + (March 2, 1999) or the American manner (February 3, 1999). Where the + form is obvious, as in 6/26/98 or 26/6/98 it ignores the switch. + + CHKDATE also recognizes dates consisting of a month and year only. + Where month and year cannot be distinguished from month and day, + CHKDATE will assume month and day. When the year is given as a two + digit number, 0 to 49 are assumed to refer to the coming 21st century + and 50-99 are 20th century dates. To force recognition as month and + year, use an apostrophe or use more than 2 digits for the year: Aug + 14 is the 14th of the month, Aug '14 is August 2014. For the + beginning of WWI, use Aug 1914 + + CHKDATE operates on a string in memory and stores the month, day and + year in the variables mon, day, and yr respectively. + + checkDate() sets up the input pointer for CHKDATE and calls it. + checkDate() then checks for error and adds 2000 to the year if the + year specified was less than 50, otherwise it adds 1900 to the year + if the year specified was less than 100. It returns non-zero in case + of error and zero otherwise. + + main() simply reads a string from stdin, and passes it to + checkDate(). If there is no error, it prints the date in a standard + format and loops forever. + +*/} + +[ + pointer input // input string in memory + ~case sensitive // ignore case + disregard white space // skip blanks and tabs + lexeme {month, roman, number} // except inside names and numbers + ~diagnose errors // diagnostics not necessary + parser name = chkdate +] + + +eof = 0 // standard asciz string terminator +white space = ' ' + '\t' // blanks and tabs +punctuation = '-' + '/' + '.' +letter = 'a-z' + +i = 'i' +v = 'v' +x = 'x' + +date string $ + -> date, eof + +date + // Feb 23, Feb 98 + -> month:m, number:d ={ + if (d > days[m] || d==0) day=0, yr=d; // (change to accommodate d = 0, made Dec. 11/99) + else day=d, mon = m, yr = thisYear; + } + + // Feb '23 + -> month:m, '\'', number:y =day = 0, mon = m, yr = y; + -> month:m, '/', number:y =day = 0, mon = m, yr = y; // Feb/99 (change made Dec. 11/99) + + // Feb 17, 98 + -> month:m, number:d, ',', number:y =day = d, mon = m, yr = y; + -> month:m, number:d, '/', number:y =day = d, mon = m, yr = y; // Feb 17/99 (change made Dec. 11/99) + + // 18 Aug + -> number:d, month =day = d, yr = thisYear; + + // 18-Aug + -> number:d, punct, month =day = d, yr = thisYear; + + // 18 aug '95 + -> number:d, month, '\''?, number:y =day = d, yr = y; + -> number:d, month, '/'?, number:y =day = d, yr = y; // 18 feb /95 (change made Dec. 11/99) + + + // 18-aug 75 or //18-aug 1923 + -> number:d, punct, month, + matchPunctuation, '\''?, number:y =day = d, yr = y; + + // 6-11 + -> number:m, punct, number:d =monthDay(m,d); + + // 6 '99 or 6-'99 + -> number:m, punct?, '\'', number:y =day = 0, mon=m, yr = y; + + // 6-6-44 or 6-6-'44 + -> number:m, punct, number:d, + matchPunctuation, '\''?, number:y =monthDayYear(m,d,y); + + // 6-11'44 + -> number:m, punct, number:d, + '\'', number:y =monthDayYear(m,d,y); + + // 6 ix + -> number:d, roman:m =mon = m, day = d, yr = thisYear; + + // 6 ix 94 + -> number:d, roman:m, number:y =mon = m, day = d, yr = y; + + // vi 44 or vi '44 + -> roman:m, '\''?, number:y =day = 0, mon = m, yr = y; + +(int) month +month + -> "jan", letter?... =1; + -> "feb", letter?... =2; + -> "mar", letter?... =3; + -> "apr", letter?... =4; + -> "may" =5; + -> "jun", letter?... =6; + -> "jul", letter?... =7; + -> "aug", letter?... =8; + -> "sep", letter?... =9; + -> "oct", letter?... =10; + -> "nov", letter?... =11; + -> "dec", letter?... =12; + + +punct + -> punctuation: c =matchChar = c; + +matchPunctuation + -> punctuation:c ={ + if (matchChar != c) PCB.exit_flag = AG_SYNTAX_ERROR_CODE; + } + +(int) number + -> '0-9':d =d-'0'; + -> number:n, '0-9':d =10*n + d-'0'; + + +(int) roman + -> i, x =9; + -> i, v =4; + -> units + + +(int) units + -> i =1; + -> v =5; + -> x =10; + -> units:x, i =x+1; + +{ + +#include <time.h> + +#define SYNTAX_ERROR + +int days[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31}; +char *monthName[13] = {NULL, "January", "February", "March", "April", + "May", "June", "July", "August", "September", "October", + "November", "December"}; +int mon = 0, day = 0, yr = 0; +int thisYear; +int european = 0; +int matchChar = 0; + +void monthDay(int m, int d) { + if (m <= 12 && d > days[m]) day=0, mon = m, yr = d; + else if (m > 12 || european ) day = m, mon =d , yr = thisYear; + else mon=m, day=d, yr=thisYear; +} + +void monthDayYear(int m, int d, int y) { + if (m > 12 || european) day = m, mon = d; + else mon = m, day = d; + yr = y; +} + +int checkDate(char *input) { + PCB.pointer = (unsigned char *) input; + chkdate(); + if (PCB.exit_flag != AG_SUCCESS_CODE) return 1; /* fail on error */ + if (mon > 12) return 1; + if (day > days[mon]) return 1; + if (yr < 50) yr += 2000; + else if (yr < 100 ) yr += 1900; + return 0; +} + +int main(int argc, char *argv[]) { + char input[82]; + time_t timeOfDay; + int k; + + for (k = 1; k < argc; k++) { + switch (*argv[k]++) { + case '/': + case '-': + if (*argv[k] == 'e') european = 1; + break; + } + } +/* Determine current year */ + + timeOfDay = time(NULL); + thisYear = localtime(&timeOfDay)->tm_year; + +/* Loop forever, reading input strings and converting them */ + while (1) { + gets(input); + if (feof(stdin)) break; + if (checkDate(input)) printf("%-30s Bad date\n", input); + else if (day) printf("%-30s %s %d, %d\n", input, monthName[mon], day, yr); + else printf("%-30s %s %d\n", input, monthName[mon], yr); + } + return 0; +} +}