Mercurial > ~dholland > hg > ag > index.cgi
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 {/* | |
2 Date Translator | |
3 Copyright (c) 1995-1999, Parsifal Software | |
4 All Rights Reserved | |
5 See the file COPYING for license and usage terms. | |
6 | |
7 This program illustrates the use of AnaGram to translate a number of | |
8 different representations of data into a common format. The example | |
9 used shows how to translate any of a number of standard formats for | |
10 entering a date into a single format for further processing. | |
11 | |
12 The parser illustrated here recognizes six basic date formats, and | |
13 for each, will supply the current year if the year is not given. If | |
14 months are entered by name, they may be spelled out in full, or | |
15 abbreviated in the customary manner. Text may be upper or lower case. | |
16 Spaces or tabs may be used freely between the elements of the dates. | |
17 Some examples of the six formats, as applied to the date June 26, | |
18 1999, are as follows: | |
19 | |
20 June 26 jun 26 June 26, 1999 JUN 26, 99 jun26,1999 | |
21 26 June 26 jun 26 June 1999 26 JUN 99 26jun99 | |
22 26-June 26-Jun 26-June-99 26-JUN-1999 | |
23 6/26 6/26/99 6/26/1999 | |
24 6-26 6-26-99 6-26-1999 | |
25 6.26 6.26.99 6-26.1999 | |
26 6/26/'99 6-26-'99 6.26.'99 | |
27 6/26 '99 6-26 '99 6.26 '99 | |
28 26/6 26/6/99 26/6/1999 | |
29 26-6 26-6-99 26-6-1999 | |
30 26.6 26.6.99 26.6.1999 | |
31 26/6 '99 26-6 '99 26.6 '99 | |
32 26 vi 26 vi 99 26 vi 1999 26 VI 99 26VI99 | |
33 26 vi '99 | |
34 | |
35 If CHKDATE encounters a date of the form 2/3/99, it interrogates a | |
36 switch to determine whether to interpret this in the European manner | |
37 (March 2, 1999) or the American manner (February 3, 1999). Where the | |
38 form is obvious, as in 6/26/98 or 26/6/98 it ignores the switch. | |
39 | |
40 CHKDATE also recognizes dates consisting of a month and year only. | |
41 Where month and year cannot be distinguished from month and day, | |
42 CHKDATE will assume month and day. When the year is given as a two | |
43 digit number, 0 to 49 are assumed to refer to the coming 21st century | |
44 and 50-99 are 20th century dates. To force recognition as month and | |
45 year, use an apostrophe or use more than 2 digits for the year: Aug | |
46 14 is the 14th of the month, Aug '14 is August 2014. For the | |
47 beginning of WWI, use Aug 1914 | |
48 | |
49 CHKDATE operates on a string in memory and stores the month, day and | |
50 year in the variables mon, day, and yr respectively. | |
51 | |
52 checkDate() sets up the input pointer for CHKDATE and calls it. | |
53 checkDate() then checks for error and adds 2000 to the year if the | |
54 year specified was less than 50, otherwise it adds 1900 to the year | |
55 if the year specified was less than 100. It returns non-zero in case | |
56 of error and zero otherwise. | |
57 | |
58 main() simply reads a string from stdin, and passes it to | |
59 checkDate(). If there is no error, it prints the date in a standard | |
60 format and loops forever. | |
61 | |
62 */} | |
63 | |
64 [ | |
65 pointer input // input string in memory | |
66 ~case sensitive // ignore case | |
67 disregard white space // skip blanks and tabs | |
68 lexeme {month, roman, number} // except inside names and numbers | |
69 ~diagnose errors // diagnostics not necessary | |
70 parser name = chkdate | |
71 ] | |
72 | |
73 | |
74 eof = 0 // standard asciz string terminator | |
75 white space = ' ' + '\t' // blanks and tabs | |
76 punctuation = '-' + '/' + '.' | |
77 letter = 'a-z' | |
78 | |
79 i = 'i' | |
80 v = 'v' | |
81 x = 'x' | |
82 | |
83 date string $ | |
84 -> date, eof | |
85 | |
86 date | |
87 // Feb 23, Feb 98 | |
88 -> month:m, number:d ={ | |
89 if (d > days[m] || d==0) day=0, yr=d; // (change to accommodate d = 0, made Dec. 11/99) | |
90 else day=d, mon = m, yr = thisYear; | |
91 } | |
92 | |
93 // Feb '23 | |
94 -> month:m, '\'', number:y =day = 0, mon = m, yr = y; | |
95 -> month:m, '/', number:y =day = 0, mon = m, yr = y; // Feb/99 (change made Dec. 11/99) | |
96 | |
97 // Feb 17, 98 | |
98 -> month:m, number:d, ',', number:y =day = d, mon = m, yr = y; | |
99 -> month:m, number:d, '/', number:y =day = d, mon = m, yr = y; // Feb 17/99 (change made Dec. 11/99) | |
100 | |
101 // 18 Aug | |
102 -> number:d, month =day = d, yr = thisYear; | |
103 | |
104 // 18-Aug | |
105 -> number:d, punct, month =day = d, yr = thisYear; | |
106 | |
107 // 18 aug '95 | |
108 -> number:d, month, '\''?, number:y =day = d, yr = y; | |
109 -> number:d, month, '/'?, number:y =day = d, yr = y; // 18 feb /95 (change made Dec. 11/99) | |
110 | |
111 | |
112 // 18-aug 75 or //18-aug 1923 | |
113 -> number:d, punct, month, | |
114 matchPunctuation, '\''?, number:y =day = d, yr = y; | |
115 | |
116 // 6-11 | |
117 -> number:m, punct, number:d =monthDay(m,d); | |
118 | |
119 // 6 '99 or 6-'99 | |
120 -> number:m, punct?, '\'', number:y =day = 0, mon=m, yr = y; | |
121 | |
122 // 6-6-44 or 6-6-'44 | |
123 -> number:m, punct, number:d, | |
124 matchPunctuation, '\''?, number:y =monthDayYear(m,d,y); | |
125 | |
126 // 6-11'44 | |
127 -> number:m, punct, number:d, | |
128 '\'', number:y =monthDayYear(m,d,y); | |
129 | |
130 // 6 ix | |
131 -> number:d, roman:m =mon = m, day = d, yr = thisYear; | |
132 | |
133 // 6 ix 94 | |
134 -> number:d, roman:m, number:y =mon = m, day = d, yr = y; | |
135 | |
136 // vi 44 or vi '44 | |
137 -> roman:m, '\''?, number:y =day = 0, mon = m, yr = y; | |
138 | |
139 (int) month | |
140 month | |
141 -> "jan", letter?... =1; | |
142 -> "feb", letter?... =2; | |
143 -> "mar", letter?... =3; | |
144 -> "apr", letter?... =4; | |
145 -> "may" =5; | |
146 -> "jun", letter?... =6; | |
147 -> "jul", letter?... =7; | |
148 -> "aug", letter?... =8; | |
149 -> "sep", letter?... =9; | |
150 -> "oct", letter?... =10; | |
151 -> "nov", letter?... =11; | |
152 -> "dec", letter?... =12; | |
153 | |
154 | |
155 punct | |
156 -> punctuation: c =matchChar = c; | |
157 | |
158 matchPunctuation | |
159 -> punctuation:c ={ | |
160 if (matchChar != c) PCB.exit_flag = AG_SYNTAX_ERROR_CODE; | |
161 } | |
162 | |
163 (int) number | |
164 -> '0-9':d =d-'0'; | |
165 -> number:n, '0-9':d =10*n + d-'0'; | |
166 | |
167 | |
168 (int) roman | |
169 -> i, x =9; | |
170 -> i, v =4; | |
171 -> units | |
172 | |
173 | |
174 (int) units | |
175 -> i =1; | |
176 -> v =5; | |
177 -> x =10; | |
178 -> units:x, i =x+1; | |
179 | |
180 { | |
181 | |
182 #include <time.h> | |
183 | |
184 #define SYNTAX_ERROR | |
185 | |
186 int days[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31}; | |
187 char *monthName[13] = {NULL, "January", "February", "March", "April", | |
188 "May", "June", "July", "August", "September", "October", | |
189 "November", "December"}; | |
190 int mon = 0, day = 0, yr = 0; | |
191 int thisYear; | |
192 int european = 0; | |
193 int matchChar = 0; | |
194 | |
195 void monthDay(int m, int d) { | |
196 if (m <= 12 && d > days[m]) day=0, mon = m, yr = d; | |
197 else if (m > 12 || european ) day = m, mon =d , yr = thisYear; | |
198 else mon=m, day=d, yr=thisYear; | |
199 } | |
200 | |
201 void monthDayYear(int m, int d, int y) { | |
202 if (m > 12 || european) day = m, mon = d; | |
203 else mon = m, day = d; | |
204 yr = y; | |
205 } | |
206 | |
207 int checkDate(char *input) { | |
208 PCB.pointer = (unsigned char *) input; | |
209 chkdate(); | |
210 if (PCB.exit_flag != AG_SUCCESS_CODE) return 1; /* fail on error */ | |
211 if (mon > 12) return 1; | |
212 if (day > days[mon]) return 1; | |
213 if (yr < 50) yr += 2000; | |
214 else if (yr < 100 ) yr += 1900; | |
215 return 0; | |
216 } | |
217 | |
218 int main(int argc, char *argv[]) { | |
219 char input[82]; | |
220 time_t timeOfDay; | |
221 int k; | |
222 | |
223 for (k = 1; k < argc; k++) { | |
224 switch (*argv[k]++) { | |
225 case '/': | |
226 case '-': | |
227 if (*argv[k] == 'e') european = 1; | |
228 break; | |
229 } | |
230 } | |
231 /* Determine current year */ | |
232 | |
233 timeOfDay = time(NULL); | |
234 thisYear = localtime(&timeOfDay)->tm_year; | |
235 | |
236 /* Loop forever, reading input strings and converting them */ | |
237 while (1) { | |
238 gets(input); | |
239 if (feof(stdin)) break; | |
240 if (checkDate(input)) printf("%-30s Bad date\n", input); | |
241 else if (day) printf("%-30s %s %d, %d\n", input, monthName[mon], day, yr); | |
242 else printf("%-30s %s %d\n", input, monthName[mon], yr); | |
243 } | |
244 return 0; | |
245 } | |
246 } |