Score compiles and lists scores.

This commit is contained in:
Neil 2023-04-06 20:21:38 -07:00
parent 5f223b1ca2
commit bdb9e171d1
8 changed files with 110 additions and 62 deletions

View File

@ -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)

View File

@ -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);

View File

@ -9,7 +9,6 @@
@std C11 */
#include "../src/kjvcite.h"
#include "../src/text.h"
#include "../src/pair.h"
#include <inttypes.h>
#include <stdio.h>

View File

@ -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;

View File

@ -9,7 +9,6 @@
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h> /* 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 <http://www.cse.yorku.ca/~oz/hash.html> 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 <stdio.h> /* 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); }

View File

@ -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);*/

View File

@ -14,7 +14,7 @@
#endif
#include "../src/journal.h"
#include "../src/scan_score.h"
#include "../src/scores.h"
#include <stdio.h>
//#include <string.h>
//#include <stdlib.h>
@ -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,
<line> * :=> skip
<line> "::" / [^:] :=> score
<score> * { why = "default score unrecognized"; goto catch; }
<score> * { 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. */
<score> @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. */
<score> @s0 keyword @s1 ":" [^\x00\n]+ / "\n" => skip {
struct pair keyword = pair(s0, s1);
/* New score. */
<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*/
<score_name> * { why = "name unrecognized"; goto catch; }
<score_date> * { why = "date unrecognized"; goto catch; }
<score_edges> * { why = "edges unrecognized"; goto catch; }
<score_name> ws* @s0 semitext+ (" " semitext+)* @s1 /* ws* */ ";"
=> score_date {
assert(score);
score->name.a = s0, score->name.b = s1;
}
<score_date> ws* "~"? @s0 date ws* ";" => score_edges {
assert(score);
if(!pair_to_date(s0, &score->date)) goto catch;
}
<score_edges> 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;
}