From dffcf0c22ff8e65828122ca74e3569c4c30304ea Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 28 Apr 2023 16:18:58 -0700 Subject: [PATCH] Added kjv. --- Makefile | 2 +- src/driver.c | 4 + src/flights.re.c | 4 +- src/kjv.re.c | 2 +- src/scan.h | 10 ++ src/scan.re.c | 249 +++++++++++++++++++++++++++++++++++++++++++++-- src/scores.re.c | 2 +- src/source.re.c | 3 +- 8 files changed, 261 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 850f6e2..7d7c43d 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ 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/scores.o -bin/scan: build/text.o build/journal.o build/pair.o build/scan.o build/driver.o +bin/scan: build/text.o build/journal.o build/kjvcite.o build/pair.o build/scan.o build/driver.o bin/%: @echo "\033[1;36mlinking $@\033[0m" diff --git a/src/driver.c b/src/driver.c index 025e190..11a1e26 100644 --- a/src/driver.c +++ b/src/driver.c @@ -40,6 +40,10 @@ int main(void) { if(!freopen(intent, "w", stdout)) goto catch; scan_flight_graph(&scn); + intent = "derived/kjv.gnu"; + if(!freopen(intent, "w", stdout)) goto catch; + scan_kjv_graph(&scn); + intent = 0; goto finally; catch: diff --git a/src/flights.re.c b/src/flights.re.c index 0efdd1d..282ab78 100644 --- a/src/flights.re.c +++ b/src/flights.re.c @@ -75,7 +75,7 @@ static int scan(struct flight_tree *const f, = {{ (uint32_t)line, {{ date.day, date.month, date.year }} }}; assert(!flight); if(line > UINT32_MAX) { why = "line overflow"; goto catch; } - switch(flight_tree_try(f, key, &flight)) { + switch(flight_tree_assign(f, key, &flight)) { /* fixme */ case TREE_PRESENT: why = "duplicate key"; case TREE_ERROR: goto catch; case TREE_ABSENT: flight->type = GLIDER; break; @@ -148,7 +148,7 @@ static int scan(struct flight_tree *const f, = {{ (uint32_t)line, {{ date.day, date.month, date.year }} }}; assert(!flight); if(line > UINT32_MAX) { why = "line overflow"; goto catch; } - switch(flight_tree_try(f, key, &flight)) { + switch(flight_tree_assign(f, key, &flight)) { case TREE_PRESENT: why = "duplicate key"; case TREE_ERROR: goto catch; case TREE_ABSENT: flight->type = POWER; break; diff --git a/src/kjv.re.c b/src/kjv.re.c index 43c5ef5..116e859 100644 --- a/src/kjv.re.c +++ b/src/kjv.re.c @@ -169,7 +169,7 @@ static int scan(union date32 date, const char *const buffer, const union line64 key = {{ (uint32_t)line, {{ date.day, date.month, date.year }} }}; struct kjvrange *value; - switch(kjvline_tree_try(lines, key, &value)) { + switch(kjvline_tree_assign(lines, key, &value)) { /* fixme */ case TREE_PRESENT: why = "duplicate key"; case TREE_ERROR: goto catch; case TREE_ABSENT: diff --git a/src/scan.h b/src/scan.h index 4c7f0e1..639f81c 100644 --- a/src/scan.h +++ b/src/scan.h @@ -64,6 +64,14 @@ struct flight { #include "../src/tree.h" +#include "kjvcite.h" +#define TREE_NAME kjvline +#define TREE_KEY union line64 +#define TREE_VALUE struct kjvrange +#define TREE_HEAD +#include "../src/tree.h" + + struct scan { struct { struct source_array array; @@ -77,6 +85,7 @@ struct scan { } scores; struct glider_tree gliders; struct flight_tree flights; + struct kjvline_tree kjvs; }; void scan_(struct scan *); @@ -84,3 +93,4 @@ struct scan scan(struct journal *); void scan_score_graph(struct scan *); void scan_glider_graph(struct scan *); void scan_flight_graph(struct scan *); +void scan_kjv_graph(struct scan *); diff --git a/src/scan.re.c b/src/scan.re.c index 3adba81..9b38c5c 100644 --- a/src/scan.re.c +++ b/src/scan.re.c @@ -65,7 +65,6 @@ static int glider_compare(const union line64 a, const union line64 b) #define TREE_BODY #include "../src/tree.h" - /* Flight tree. */ static void flight_to_string(const union line64 line, const struct flight *f, char (*const a)[12]) { (void)f; date32_to_string(line.date, a); } @@ -79,12 +78,25 @@ static int flight_compare(const union line64 a, const union line64 b) #define TREE_BODY #include "../src/tree.h" +/* KJV tree. */ +static void kjvline_to_string(const union line64 line, const struct kjvrange *u, + char (*const a)[12]) { (void)u; date32_to_string(line.date, a); } +static int kjvline_compare(const union line64 a, const union line64 b) + { return a.u64 > b.u64; } +#define TREE_NAME kjvline +#define TREE_KEY union line64 +#define TREE_VALUE struct kjvrange +#define TREE_COMPARE +#define TREE_TO_STRING +#define TREE_BODY +#include "../src/tree.h" + /*!conditions:re2c*/ static int scan_day(struct scan *const scan, union date32 date, const char *const buffer) { - const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *s0, *s1, *t0, *t1; + const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *yyt3, *s0, *s1, *t0, *t1; enum YYCONDTYPE condition = yycline; size_t line = 1; char datestr[12] = {0}; @@ -92,6 +104,9 @@ static int scan_day(struct scan *const scan, union date32 date, struct score *new_score = 0; struct glider *new_glider = 0; struct flight *new_flight = 0; + enum kjv_book book = Revelation; + uint32_t chapter = 0, verse = 0, verse_end = 0; + assert(scan && date.u32 && buffer); YYCURSOR = YYMARKER = yyt1 = buffer; /*!re2c /**/ @@ -112,6 +127,10 @@ static int scan_day(struct scan *const scan, union date32 date, date = natural "-" [0-1][0-9] "-" [0-3][0-9]; minutes = [0-5][0-9]; airport = [A-Z0-9]{4,4}; + kjvlookat = ws* natural ":" natural [ab]? ("-" natural [ab]?)? ws+ "--" ws+; + first = ("I" | "1") " "?; + second = ("II" | "2") " "?; + third = ("III" | "3") " "?; */ for( ; ; ) { /*!re2c /**/ @@ -379,6 +398,125 @@ static int scan_day(struct scan *const scan, union date32 date, { new_flight->remarks.a = s0, new_flight->remarks.b = s1; new_flight = 0; line++; continue; } + + /* Books in KJV. */ + "Genesis" / kjvlookat => book { book = Genesis; continue; } + "Exodus" / kjvlookat => book { book = Exodus; continue; } + "Leviticus" / kjvlookat => book { book = Leviticus; continue; } + "Numbers" / kjvlookat => book { book = Numbers; continue; } + "Deuteronomy" / kjvlookat => book + { book = Deuteronomy; continue; } + "Joshua" / kjvlookat => book { book = Joshua; continue; } + "Judges" / kjvlookat => book { book = Judges; continue; } + "Ruth" / kjvlookat => book { book = Ruth; continue; } + first "Samuel" / kjvlookat => book { book = ISamuel; continue; } + second "Samuel" / kjvlookat => book { book = IISamuel; continue; } + first "Kings" / kjvlookat => book { book = IKings; continue; } + second "Kings" / kjvlookat => book { book = IIKings; continue; } + first "Chronicles" / kjvlookat + => book { book = IChronicles; continue; } + second "Chronicles" / kjvlookat + => book { book = IIChronicles; continue; } + "Ezra" / kjvlookat => book { book = Ezra; continue; } + "Nehemiah" / kjvlookat => book { book = Nehemiah; continue; } + "Esther" / kjvlookat => book { book = Esther; continue; } + "Job" / kjvlookat => book { book = Job; continue; } + "Psalms" / kjvlookat => book { book = Psalms; continue; } + "Proverbs" / kjvlookat => book { book = Proverbs; continue; } + "Ecclesiastes" / kjvlookat + => book { book = Ecclesiastes; continue; } + "Song of Solomon" / kjvlookat + => book { book = Song_of_Solomon; continue; } + "Isaiah" / kjvlookat => book { book = Isaiah; continue; } + "Jeremiah" / kjvlookat => book { book = Jeremiah; continue; } + "Lamentations" / kjvlookat + => book { book = Lamentations; continue; } + "Ezekiel" / kjvlookat => book { book = Ezekiel; continue; } + "Daniel" / kjvlookat => book { book = Daniel; continue; } + "Hosea" / kjvlookat => book { book = Hosea; continue; } + "Joel" / kjvlookat => book { book = Joel; continue; } + "Amos" / kjvlookat => book { book = Amos; continue; } + "Obadiah" / kjvlookat => book { book = Obadiah; continue; } + "Jonah" / kjvlookat => book { book = Jonah; continue; } + "Micah" / kjvlookat => book { book = Micah; continue; } + "Nahum" / kjvlookat => book { book = Nahum; continue; } + "Habakkuk" / kjvlookat => book { book = Habakkuk; continue; } + "Zephaniah" / kjvlookat => book { book = Zephaniah; continue; } + "Haggai" / kjvlookat => book { book = Haggai; continue; } + "Zechariah" / kjvlookat => book { book = Zechariah; continue; } + "Malachi" / kjvlookat => book { book = Malachi; continue; } + "Matthew" / kjvlookat => book { book = Matthew; continue; } + "Mark" / kjvlookat => book { book = Mark; continue; } + "Luke" / kjvlookat => book { book = Luke; continue; } + "John" / kjvlookat => book { book = John; continue; } + "Acts" / kjvlookat => book { book = Acts; continue; } + "Romans" / kjvlookat => book { book = Romans; continue; } + first "Corinthians" / kjvlookat + => book { book = ICorinthians; continue; } + second "Corinthians" / kjvlookat + => book { book = IICorinthians; continue; } + "Galatians" / kjvlookat => book { book = Galatians; continue; } + "Ephesians" / kjvlookat => book { book = Ephesians; continue; } + "Philippians" / kjvlookat => book + { book = Philippians; continue; } + "Colossians" / kjvlookat => book { book = Colossians; continue; } + first "Thessalonians" / kjvlookat + => book { book = IThessalonians; continue; } + second "Thessalonians" / kjvlookat + => book { book = IIThessalonians; continue; } + first "Timothy" / kjvlookat => book + { book = ITimothy; continue; } + second "Timothy" / kjvlookat => book + { book = IITimothy; continue; } + "Titus" / kjvlookat => book { book = Titus; continue; } + "Philemon" / kjvlookat => book { book = Philemon; continue; } + "Hebrews" / kjvlookat => book { book = Hebrews; continue; } + "James" / kjvlookat => book { book = James; continue; } + first "Peter" / kjvlookat => book { book = IPeter; continue; } + second "Peter" / kjvlookat => book { book = IIPeter; continue; } + first "John" / kjvlookat => book { book = IJohn; continue; } + second "John" / kjvlookat => book { book = IIJohn; continue; } + third "John" / kjvlookat => book { book = IIIJohn; continue; } + "Jude" / kjvlookat => book { book = Jude; continue; } + "Revelation" / kjvlookat => book { book = Revelation; continue; } + * { fail = "kjv unrecognized"; goto catch; } + /* 19:15a, just ignore the a. */ + ws+ @s0 natural @s1 ":" @t0 natural @t1 [ab]? { + if(chapter || verse || verse_end) + { fail = "kjv reference"; goto catch; } + if(!pair_to_natural(s0, s1, &chapter) + || !pair_to_natural(t0, t1, &verse)) + { fail = "kjv reference numerical error"; goto catch; } + continue; + } + "-" @s0 natural @s1 [ab]? { /* Verse range. */ + if(!chapter || !verse || verse_end) + { fail = "kjv range unrecognized"; goto catch; } + if(!pair_to_natural(s0, s1, &verse_end)) + { fail = "kjv range numerical error"; goto catch; } + continue; + } + ws+ "--" ws+ => skip { + if(!chapter || !verse) + { fail = "kjv missing information"; goto catch; } + if(verse_end && verse_end <= verse) + { fail = "kjv interval error"; goto catch; } + const union line64 key = {{ (uint32_t)line, date }}; + struct kjvrange *value; + switch(kjvline_tree_bulk_assign(&scan->kjvs, key, &value)) { + case TREE_PRESENT: fail = "kjv duplicate key"; + case TREE_ERROR: goto catch; + case TREE_ABSENT: + value->start.book = book; + value->start.chapter = chapter; + value->start.verse = verse; + value->verse_end = verse_end; + break; + } + book = Revelation, chapter = 0, verse = 0, verse_end = 0; + continue; + } + */ } assert(0); /* Never gets here. */ catch: @@ -424,14 +562,9 @@ struct scan scan(struct journal *const jrnl) { if(!linemap_tree_bulk_finish(&scan.sources.dates) || !linemap_tree_bulk_finish(&scan.scores.dates) || !glider_tree_bulk_finish(&scan.gliders) - || !flight_tree_bulk_finish(&scan.flights)) goto catch; + || !flight_tree_bulk_finish(&scan.flights) + || !kjvline_tree_bulk_finish(&scan.kjvs)) goto catch; - fprintf(stderr, "List of scores: %s.\n" - "Mapped to indices: %s.\n" - "Date-line tree: %s.\n", - score_array_to_string(&scan.scores.array), - pair_map_table_to_string(&scan.scores.map), - linemap_tree_to_string(&scan.scores.dates)); goto finally; catch: scan_(&scan); @@ -652,3 +785,101 @@ void scan_flight_graph(struct scan *const scan) { " (43200):(total/2.):(getIndex(strcol(2))) w boxxy lc var, \\\n" " for [i=1:words(Uniqs)] keyentry w boxxy lc i ti Uniq(i)\n"); } + +void scan_kjv_graph(struct scan *const scan) { + struct kjvcount_table count = {0}; + struct kjvset_table set = kjv_set(); + size_t no_total; + const char *reason = 0; + + count = kjv_count(&no_total); + fprintf(stderr, "KJV count: %s.\n", kjv_count_to_string(&count)); + if(!no_total) { reason = "kjv failed to load"; goto catch; } + + fprintf(stderr, "KJV lines: %s.\n", kjvline_tree_to_string(&scan->kjvs)); + + struct kjvline_tree_iterator it = kjvline_tree_iterator(&scan->kjvs); + + /* https://stackoverflow.com/a/12601553 */ + printf("set terminal pngcairo dashed transparent truecolor" + " size 840, 480 fontscale 1\n" + "set output \"kjv.png\"\n"); + printf("$Data <name.a) { errno = EDOM; goto catch; } + date32_to_string(line.date, &datestr); /* Date. */ + kjvcite_to_string(range->start, &citestr); /* KJV cite. */ + for(union kjvcite c = range->start; ; c.verse++) { + size_t w = kjv_count_get(&count, c); + words += w; + switch (kjv_set_add(&set, c)) { + case TABLE_ERROR: goto catch; + case TABLE_ABSENT: newwords += w; + case TABLE_PRESENT: break; + } /* while(); */ + if(!range->verse_end || range->verse_end <= c.verse) break; + } + printf("%s, %s", datestr, citestr); + if(range->verse_end) printf("-%" PRIu32, range->verse_end); + printf(", %zu, %zu, %.*s\n", + words, newwords, (int)(src->name.b - src->name.a), src->name.a); + } + printf("EOD\n" + "# theozh https://stackoverflow.com/a/75466214/2472827\n" + "# get a unique list from datablock\n" + "addToList(list,col) = list.( strstrt(list,'\"'.strcol(col).'\"') \\\n" + " > 0 ? '' : ' \"'.strcol(col).'\"')\n" + "Uniqs = ''\n" + "stats $Data u (Uniqs=addToList(Uniqs,5)) nooutput\n" + "Uniq(i) = word(Uniqs,i)\n" + "getIndex(s) = sum [_i=1:words(Uniqs)] s eq word(Uniqs,_i) ? _i : 0\n" + "\n" + "stats $Data u 3 nooutput\n" + "cumsum = STATS_sum\n" + "stats $Data u 4 nooutput\n" + "setsum = STATS_sum\n" + "\n" + "myTimeFmt = \"%%Y-%%m-%%d\"\n" + "set format x myTimeFmt timedate\n" + "set xtics format myTimeFmt rotate by -30\n" + "set format y \"%%g%%%%\"\n" + "set grid\n" + "set key out reverse Left noautotitle\n" + "set style fill solid 0.5\n" + "unset border\n" + "set autoscale xfix # max? hack: can't get x to extend further\n" + "\n" + "set label sprintf(\"%%u cumulative words (duplicate verses counted)\"," + " cumsum) center at graph 0.5, first cumsum*100/%zu offset 0,0.5\n" + "set label sprintf(\"%%u unique KJV verse words memorized\", setsum) " + "center at graph 0.5, first setsum*100/%zu offset 0,0.5\n" + "\n" + "plot \\\n" + " cumsum*100/%zu w l lc \"grey\" dt 2 lw 1, \\\n" + " total=0 $Data u" + " (timecolumn(1,myTimeFmt)):(dy=$3*100/%zu,total=total+dy) \\\n" + " w steps lc \"grey\" dt 2 lw 1, \\\n" /* `pngcairo` has trouble :[. */ + " total=0 $Data u" + " (timecolumn(1,myTimeFmt)):(dy=$4*100/%zu,total=total+dy) \\\n" + " w steps lc \"black\" dt 1 lw 1, \\\n" + " setsum*100/%zu w l lc \"black\" dt 1 lw 1, \\\n" + " total=0 '' u \\\n" + " (timecolumn(1,myTimeFmt)): \\\n" + " (dy=$4*100/%zu,total=total+dy,total/2.): \\\n" + " (43200): \\\n" + " (total/2.): \\\n" + " (getIndex(strcol(5))) w boxxy lc var lw 1, \\\n" + " for [i=1:words(Uniqs)] keyentry w boxxy lc i ti Uniq(i)\n", + no_total, no_total, no_total, no_total, no_total, no_total, no_total); + goto finally; +catch: + perror(reason); +finally: + kjv_count_(&count); +} diff --git a/src/scores.re.c b/src/scores.re.c index 98b99b8..08117b0 100644 --- a/src/scores.re.c +++ b/src/scores.re.c @@ -91,7 +91,7 @@ static int scan(union date32 date, const char *const buffer, if(scores->list.data[idx].last.u32 >= date.u32) { why = "duplicate key in same day"; goto catch; } scores->list.data[idx].last.u32 = date.u32; - switch(score_tree_bulk_try(&scores->dates, key, &pidx)) { + switch(score_tree_bulk_assign(&scores->dates, key, &pidx)) { case TREE_PRESENT: assert(0); why = "duplicate key"; /* _Sic_. */ case TREE_ERROR: goto catch; case TREE_ABSENT: *pidx = idx; break; diff --git a/src/source.re.c b/src/source.re.c index cbdebe2..673c49c 100644 --- a/src/source.re.c +++ b/src/source.re.c @@ -82,7 +82,8 @@ static int scan(union date32 date, const char *const buffer, { errno = ERANGE; why = "too many lines of text"; goto catch; } if(!(i = pair_map_table_get(&s->map, keyword))) { why = "keyword not introduced"; goto catch; } - switch(source_tree_try(&s->dates, key, &pi)) { + /* fixme: bulk */ + switch(source_tree_assign(&s->dates, key, &pi)) { case TREE_PRESENT: why = "duplicate key"; /* _Sic_. */ case TREE_ERROR: goto catch; case TREE_ABSENT: *pi = i; break;