Mercurial > ~dholland > hg > ag > index.cgi
view tests/agcl/parsifal/date_p1.syn @ 9:60b08b68c750
Switch to static inline as an expedient build fix.
Should probably set this up with working C99 inline but for the moment
I don't have the energy.
author | David A. Holland |
---|---|
date | Mon, 30 May 2022 23:56:45 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
{/* 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; } }