diff --git a/Makefile b/Makefile index c063834..437e573 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ bin/test-source: build/text.o build/pair.o build/journal.o build/source.o build/ bin/test-kjv: build/text.o build/pair.o build/kjvcite.o build/test_kjv.o bin/kjv: build/text.o build/pair.o build/journal.o build/kjvcite.o build/kjv.o build/source.o bin/flight: build/text.o build/pair.o build/journal.o build/source.o build/flights.o build/flighthours.o -bin/score: build/text.o build/pair.o build/journal.o build/scan_score.o +bin/score: build/text.o build/pair.o build/journal.o build/scores.o bin/%: @echo "\033[1;36mlinking $@\033[0m" @@ -72,7 +72,7 @@ build/%.c: src/%.re.c # # https://github.com/neil-edelman/cdoc documentation # -cdoc -o $@ $< -.SECONDARY: build/kjv.c build/journal.c build/source.c build/scan_kjv.c build/flights.c build/kjvcite.c +.SECONDARY: build/kjv.c build/journal.c build/source.c build/scan_kjv.c build/flights.c build/kjvcite.c build/scores.c .PHONY: clean release test test: $(projects) diff --git a/src/journal.re.c b/src/journal.re.c index d824575..d241c86 100644 --- a/src/journal.re.c +++ b/src/journal.re.c @@ -244,13 +244,6 @@ struct journal_iterator journal_iterator(struct journal *const j) { return it; } -/*struct journal_iterator journal_begin_at(struct journal *const j, - const union date32 x) { - struct journal_iterator it; - it._ = day_tree_begin_at(&j->days, x); - return it; -}*/ - int journal_next(struct journal_iterator *const it, union date32 *const k, const char **v) { assert(it && k && v); diff --git a/src/kjvcite.re.c b/src/kjvcite.re.c index b933d50..184a497 100644 --- a/src/kjvcite.re.c +++ b/src/kjvcite.re.c @@ -9,7 +9,6 @@ @std C11 */ #include "../src/kjvcite.h" -#include "../src/text.h" #include "../src/pair.h" #include #include diff --git a/src/not-used.c b/src/not-used.c index a907cf7..8621ac2 100644 --- a/src/not-used.c +++ b/src/not-used.c @@ -1,27 +1,3 @@ -/** Is `y` a leap-year? */ -static int leap(int y) { - assert(y >= 1582); - if(!(y % 400)) return 1; - if(!(y % 100)) return 0; - if(!(y % 4)) return 1; - return 0; -} -/** Convert or narrower type or return zero. */ -static union date32 date_to_32(const int y, const int m, const int d) { - union date32 d32 = { 0 }; - /* Leap year calculations only work at y>=1 and Gregorian Calendar and max - 23 bits. */ - if(y < 1582 || y > 8388607 || m < 1 || m > 12 || d < 1 || d > 31) goto no; - switch(m) { - case 1: case 3: case 5: case 7: case 8: case 10: case 12: break; - case 4: case 6: case 9: case 11: if(d > 30) goto no; break; - case 2: if(d > 28 + leap(y)) goto no; break; - default: assert(0); break; - } - d32.year = (unsigned)y, d32.month = (unsigned)m, d32.day = (unsigned)d; -no: - return d32; -} /** Tomohiko Sakamoto comp.lang.c 1993-04-10. */ static unsigned weekday(union date32 d) { d.year -= d.month < 3; diff --git a/src/pair.c b/src/pair.c index 20a8cae..1587206 100644 --- a/src/pair.c +++ b/src/pair.c @@ -9,7 +9,6 @@ #include #include #include -#include /* sprintf */ /** @return Constructs `a` and `b` as a pair. */ struct pair pair(const char *const a, const char *const b) { @@ -19,14 +18,14 @@ struct pair pair(const char *const a, const char *const b) { } /** Doesn't check if the number is actually in [0, 9]. - @return Whether it was able to parse unsigned `p` to `n`. */ -int pair_to_natural(const char *s, const char *const e, uint32_t *const n) { + @return Whether it was able to parse unsigned [`a`, `b`] to `n`. */ +int pair_to_natural(const char *a, const char *const b, uint32_t *const n) { uint32_t accum = 0; - while(s < e) { - unsigned next = accum * 10 + (unsigned)(*s - '0'); + while(a < b) { + unsigned next = accum * 10 + (unsigned)(*a - '0'); if(accum > next) return errno = ERANGE, 0; accum = next; - s++; + a++; } return *n = accum, 1; } @@ -69,6 +68,53 @@ int pair_is_string(struct pair x, const char *y) { while(x.a < x.b) { if(*x.a != *y || !*y) return 0; x.a++, y++; } return !*y; } +/** Is `y` a leap-year? */ +static int leap(int y) { + assert(y >= 1582); + if(!(y % 400)) return 1; + if(!(y % 100)) return 0; + if(!(y % 4)) return 1; + return 0; +} +/** Convert or narrower type or return zero. */ +static union date32 date_to_32(const uint32_t y, const uint32_t m, + const uint32_t d) { + union date32 d32 = { 0 }; + /* Leap year calculations only work at y>=1 and Gregorian Calendar and max + 23 bits. */ + if(y < 1582 || y > 8388607 || m < 1 || m > 12 || d < 1 || d > 31) goto no; + switch(m) { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: break; + case 4: case 6: case 9: case 11: if(d > 30) goto no; break; + case 2: if(d > (uint32_t)(28 + leap((int)y))) goto no; break; + default: assert(0); break; + } + d32.year = (unsigned)y, d32.month = (unsigned)m, d32.day = (unsigned)d; +no: + return d32; +} +/** `a` represents the start of a date in y...-mm-dd, which is stored in `d`. + @return Success. + @throws[ERANGE] Year is more then 23 bits. + @throws[EILSEQ] The is not a date? */ +int pair_to_date(const char *a, union date32 *const d) { + uint32_t year = 0, month, day; + union date32 temp; + assert(a && d); + while(*a >= '0' && *a <= '9') { + year = year * 10 + (unsigned)(*a - '0'); + if(year > 0x7FFFFF) return errno = ERANGE, 0; /* 23 bits */ + a++; + } + if(a[0] != '-' || a[1] == '\0' || a[2] == '\0' + || a[3] != '-' || a[4] == '\0' || a[5] == '\0') + return errno = EILSEQ, 0; + month = (unsigned)(a[1] - '0') * 10 + (unsigned)(a[2] - '0'); + day = (unsigned)(a[4] - '0') * 10 + (unsigned)(a[5] - '0'); + temp = date_to_32(year, month, day); + if(!temp.u32) return errno = EILSEQ, 0; + return *d = temp, 1; +} /** @return A djb2 hash of `p`. */ static uint32_t pair_djb2(struct pair p) { @@ -80,6 +126,7 @@ static uint32_t pair_djb2(struct pair p) { return hash; } +#include /* sprintf */ /* Maps from substring keywords to indices, default zero. */ static void pairmap_to_string(const struct pair key, const size_t i, char (*const a)[12]) { (void)key; sprintf(*a, "%zu", i); } diff --git a/src/pair.h b/src/pair.h index 56e769b..38b3ee1 100644 --- a/src/pair.h +++ b/src/pair.h @@ -12,6 +12,8 @@ int pair_hours_to_minutes(const char *h0, const char *const h1, const char *m0, const char *const m1, uint32_t *const n); int pair_is_equal(struct pair, struct pair); int pair_is_string(struct pair, const char *); +#include "journal.h" /* date32 */ +int pair_to_date(const char *a, union date32 *const d); /*fixme uint32_t pair_djb2(const struct pair p);*/ diff --git a/src/scan_score.h b/src/scores.h similarity index 100% rename from src/scan_score.h rename to src/scores.h diff --git a/src/scan_score.re.c b/src/scores.re.c similarity index 68% rename from src/scan_score.re.c rename to src/scores.re.c index 3371dba..534b3c0 100644 --- a/src/scan_score.re.c +++ b/src/scores.re.c @@ -14,7 +14,7 @@ #endif #include "../src/journal.h" -#include "../src/scan_score.h" +#include "../src/scores.h" #include //#include //#include @@ -56,11 +56,12 @@ static int score_compare(const union line64 a, const union line64 b) static int scan(union date32 date, const char *const buffer, struct scores *const scores) { - const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *yyt3, *s0, *s1, *t0, *t1; + const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *s0, *s1; enum YYCONDTYPE condition = yycline; size_t line = 1; char datestr[12] = {0}; const char *why = "unexpected"; + struct score *score = 0; assert(buffer && scores); YYCURSOR = YYMARKER = yyt1 = buffer; /*!re2c /**/ @@ -71,11 +72,13 @@ static int scan(union date32 date, const char *const buffer, re2c:define:YYGETCONDITION:naked = 1; re2c:define:YYSETCONDITION:naked = 1; - unix_control = [\x01-\x08\x0b-\x1f\x7f]; ws = [ \t]; - glyph = [^] \ ("\x00" | "\n" | unix_control | ws); + glyph = [^\x00-\x20\x7f]; // [^\x00\n\t ] + all weird + semitext = glyph \ ";"; natural = [1-9][0-9]*; + uint = [0-9]+; keyword = [A-Za-z0-9][A-Za-z0-9_-]*; + date = natural "-" [0-1][0-9] "-" [0-3][0-9]; */ for( ; ; ) { /*!re2c /**/ /* Default ignore. */ @@ -86,53 +89,74 @@ static int scan(union date32 date, const char *const buffer, * :=> skip "::" / [^:] :=> score - * { why = "default score unrecognized"; goto catch; } + * { why = "score unrecognized"; goto catch; } + /* Already there. Use the map to get the index from the keyword and + then stick a marker in the tree with that index. */ @s0 keyword @s1 / "\n" => skip { also_add_to_tree: { const struct pair keyword = pair(s0, s1); const union line64 key = { { (uint32_t)line, date } }; - size_t i, *pi; + size_t idx, *pidx; if(line > UINT32_MAX) { errno = ERANGE; why = "too many lines of text"; goto catch; } - if(!(i = pair_map_table_get(&scores->map, keyword))) + if(!(idx = pair_map_table_get(&scores->map, keyword))) { why = "keyword not introduced"; goto catch; } - switch(score_tree_try(&scores->dates, key, &pi)) { + /* fixme: bulk */ + switch(score_tree_try(&scores->dates, key, &pidx)) { case TREE_PRESENT: why = "duplicate key"; /* _Sic_. */ case TREE_ERROR: goto catch; - case TREE_ABSENT: *pi = i; break; + case TREE_ABSENT: *pidx = idx; break; } - /*date32_to_string(date, &datestr); - printf("%s: <%.*s>\n", datestr, (int)(s1 - s0), s0);*/ + date32_to_string(date, &datestr); + printf("%s: <%.*s>\n", datestr, (int)(s1 - s0), s0); continue; } } - /* This is lazy and will pickup trailing spaces. */ - @s0 keyword @s1 ":" [^\x00\n]+ / "\n" => skip { - struct pair keyword = pair(s0, s1); + /* New score. */ + @s0 keyword @s1 ":" => score_name { size_t *idx; - struct score *score; - switch(pair_map_table_assign(&scores->map, keyword, &idx)) { + switch(pair_map_table_assign(&scores->map, pair(s0, s1), &idx)) { case TABLE_PRESENT: errno = EDOM; why = "new keyword already used"; - case TABLE_ERROR: goto catch; /* /\ _Sic_. */ - case TABLE_ABSENT: *idx = 0; break; /* Good. */ + case TABLE_ERROR: goto catch; /* _Sic_. */ + case TABLE_ABSENT: *idx = 0; break; } if(!(score = scorelist_array_new(&scores->list))) goto catch; *idx = (size_t)(score - scores->list.data); /*struct pair key, name; union date32 date; unsigned edges;*/ score->key.a = s0, score->key.b = s1; score->name.a = 0, score->name.b = 0; - score->date.year = 0, score->date.month = 0, score->date.day = 0; + score->date.u32 = 0; score->edges = 0; date32_to_string(date, &datestr); - fprintf(stderr, "%s: new source <%.*s> stored in list at %zu.\n", + fprintf(stderr, "%s: new score <%.*s> stored in list at %zu.\n", datestr, (int)(s1 - s0), s0, *idx); goto also_add_to_tree; } + /*ws* @name0 [^\x00\n;]+ @name1 ";" + ws* @year0 natural @year1 "-" @month [0-1][0-9] "-" @day [0-1][0-9] ";" + ws* + / "\n" => skip*/ + * { why = "name unrecognized"; goto catch; } + * { why = "date unrecognized"; goto catch; } + * { why = "edges unrecognized"; goto catch; } + ws* @s0 semitext+ (" " semitext+)* @s1 /* ws* */ ";" + => score_date { + assert(score); + score->name.a = s0, score->name.b = s1; + } + ws* "~"? @s0 date ws* ";" => score_edges { + assert(score); + if(!pair_to_date(s0, &score->date)) goto catch; + } + ws* "~"? @s0 uint @s1 ws* / "\n" => skip { + assert(score); + if(!pair_to_natural(s0, s1, &score->edges)) goto catch; + score = 0; /* Done. */ + } */ } assert(0); /* Never gets here. */ catch: if(!errno) errno = EILSEQ; date32_to_string(date, &datestr); - fprintf(stderr, "%s\n" - "%s line %zu: %s.\n", buffer, datestr, line, why); + fprintf(stderr, "%s line %zu: %s.\n", datestr, line, why); return 0; } @@ -172,3 +196,10 @@ finally: int scores_is_empty(const struct scores *const s) { return !s || !s->dates.root.node; } + +int main(void) { + struct journal j = journal(); + struct scores s = scores(&j); + scores_(&s); + return EXIT_SUCCESS; +}