WIP on parser

This commit is contained in:
Laurence Withers 2006-10-15 22:11:17 +01:00
parent ff268cded0
commit d61e77f9dc
3 changed files with 340 additions and 4 deletions

View File

@ -6,7 +6,7 @@
*/
/* parse.c */
void iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
struct iso8601_details* details);
/* c_library.c */

View File

@ -7,10 +7,272 @@
void iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
struct iso8601_details* details)
{
enum {
state_none,
state_year, // e.g. `2006' or `2006123'
state_date2, // 2nd component of date, e.g. `2006-' or `2006-1'
state_day, // e.g. `2006-01-' or `2006-01-01'
state_week_basic, // e.g. `2006W' or `2006W123'
state_week_extended, // e.g. `2006-W' or `2006-W31'
state_week_day, // e.g. `2006-W31-'
state_week_done, // `2006-W31-1'
state_time_basic,
state_time_hour
}state = state_none;
char ch;
int num = 0, neg = 0, dig = 0;
int y = 0, m = 0, d = 0, w = 0, wd = 0, hour = 0, min = 0, sec = 0;
while(1) {
ch = *str++;
printf("ch = '%c', state = %d, num = %d, dig = %d\n", ch, state, num, dig);
switch(state) {
case state_none:
switch(ch) {
case '0' ... '9':
state = state_year;
num = ch - '0';
++dig;
break;
case '-':
neg = 1;
state = state_year;
break;
default:
errno = EILSEQ;
return -1;
}
break;
case state_year:
switch(ch) {
case '0' ... '9':
++dig;
num *= 10;
num += ch - '0';
if(num > 1000000000) {
errno = EDOM;
return -1;
}
break;
case '-':
if(!dig) {
errno = EILSEQ;
return -1;
}
y = num;
num = 0;
dig = 0;
state = state_date2;
break;
case 'T':
case 0:
switch(dig) {
case 4:
if(ch) {
errno = EILSEQ;
return -1;
}
y = num;
goto done;
case 6:
if(ch) {
errno = EILSEQ;
return -1;
}
y = num / 100;
m = num - y * 100;
goto done;
case 7:
y = num / 1000;
d = num - (y * 1000);
break;
case 8:
y = num / 10000;
num -= y * 10000;
m = num / 100;
d = num - m * 100;
break;
default:
errno = EILSEQ;
return -1;
}
if(!ch) goto done;
state = state_time_basic;
num = 0;
dig = 0;
break;
case 'W':
y = num;
num = 0;
dig = 0;
state = state_week_basic;
break;
}
break;
case state_date2:
switch(ch) {
case '0' ... '9':
num *= 10;
num += ch - '0';
++dig;
break;
case '-':
if(num < 1 || num > 12 || dig != 2) {
errno = EDOM;
return -1;
}
m = num;
num = 0;
dig = 0;
state = state_day;
case 'W':
if(dig) {
errno = EILSEQ;
return -1;
}
state = state_week_extended;
break;
case 0:
case 'T':
if(dig != 3) {
errno = EILSEQ;
return -1;
}
d = num;
if(!ch) goto done;
state = state_time_hour;
num = 0;
dig = 0;
break;
default:
errno = EILSEQ;
return -1;
}
break;
case state_day:
switch(ch) {
case '0' ... '9':
num *= 10;
num += ch;
++dig;
break;
case 0:
case 'T':
if(dig != 2) {
errno = EILSEQ;
return -1;
}
d = num;
if(!ch) goto done;
state = state_time_hour;
break;
default:
errno = EILSEQ;
return -1;
}
break;
case state_week_basic:
switch(ch) {
case '0' ... '9':
num *= 10;
num += ch - '0';
++dig;
break;
case 0:
case 'T':
switch(dig) {
case 3:
w = num / 10;
wd = num % 10;
break;
case 2:
w = num;
if(!ch) break;
default:
errno = EILSEQ;
return -1;
}
if(!ch) goto done;
break;
}
break;
case state_week_extended:
switch(ch) {
case '0' ... '9':
num *= 10;
num += ch - '0';
++dig;
break;
case 0:
case '-':
if(dig != 2) {
errno = EILSEQ;
return -1;
}
w = num;
num = 0;
dig = 0;
if(!ch) goto done;
state = state_week_day;
break;
}
break;
case state_week_day:
if(ch < '1' || ch > '7') {
errno = EILSEQ;
return -1;
}
wd = ch - '0';
state = state_week_done;
break;
case state_week_done:
if(!ch) goto done;
if(ch != 'T') {
errno = EILSEQ;
return -1;
}
state = state_time_hour;
break;
default:
goto done;
}
}
done:
printf("y=%d, m=%d, d=%d, w=%d, wd=%d\n", y, m, d, w, wd);
abort();
}

74
src/tests/parser.c Normal file
View File

@ -0,0 +1,74 @@
/* libiso8601/src/tests/parser.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#include "iso8601.h"
#include <stdio.h>
#include <string.h>
int do_date(const char* str)
{
struct iso8601_date earliest, latest;
struct iso8601_details details;
char buf[100], buf2[100];
if(iso8601_parse(str, &earliest, &latest, &details)) {
perror("iso8601_parse");
return 1;
}
iso8601_print(buf, sizeof(buf), &earliest, &details);
iso8601_print(buf2, sizeof(buf2), &latest, &details);
printf("Results for ``%s'':\n"
" Earliest: day=%d, sec=%05d, nsec=%09d; %s\n"
" Latest : day=%d, sec=%05d, nsec=%09d; %s\n"
" Details : date_prec=%d, time_prec=%d, extended=%d, tz_sec=%d\n"
"\n",
str,
earliest.day, earliest.sec, earliest.nsec, buf,
latest.day, latest.sec, latest.nsec, buf2,
details.date_prec, details.time_prec, details.extended, details.tz_sec);
return 0;
}
int main(int argc, char* argv[])
{
int ret = 0, i;
char buf[100];
if(argc == 2 && !strcmp(argv[1], "--print-summary")) {
printf("One line summary.\n");
return 0;
}
if(argc == 1) {
while(!feof(stdin)) {
printf("date >> ");
scanf("%s", buf);
do_date(buf);
}
return 0;
}
for(i = 1; i < argc; ++i) {
ret |= do_date(argv[i]);
}
return ret;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/