Got it almost working in theory with utf-8?

This commit is contained in:
2025-09-21 20:25:29 -07:00
parent b9cb570691
commit d277afc48c
3 changed files with 130 additions and 106 deletions

View File

@@ -20,43 +20,42 @@ 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 [`a`, `b`] to `n`. */
int pair_to_natural(const char *a, const char *const b, uint32_t *const n) {
int pair_to_natural(struct pair p, uint32_t *const n) {
uint32_t accum = 0;
while(a < b) {
unsigned next = accum * 10 + (unsigned)(*a - '0');
while(p.a < p.b) {
unsigned next = accum * 10 + (unsigned)(p.a - '0');
if(accum > next) return errno = ERANGE, 0;
accum = next;
a++;
p.a++;
}
return *n = accum, 1;
}
static int pair_to_64(const char *a, const char *const b, uint64_t *const n) {
static int pair_to_64(struct pair p, uint64_t *const n) {
uint64_t accum = 0;
while(a < b) {
uint64_t next = accum * 10 + (uint64_t)(*a - '0');
while(p.a < p.b) {
uint64_t next = accum * 10 + (uint64_t)(p.a - '0');
if(accum > next) return errno = ERANGE, 0;
accum = next;
a++;
p.a++;
}
return *n = accum, 1;
}
/** `h0` "1" `h1` ":" `m0` "30" `m1` -> 90 `n` @return Valid. */
int pair_colon_to_minutes(const char *h0, const char *const h1,
const char *m0, const char *const m1, uint32_t *const n) {
/** `h` "1" ":" `m` "30" -> 90 `n` @return Valid. */
int pair_colon_to_minutes(struct pair h, struct pair m, uint32_t *const n) {
uint32_t hours, minutes;
return pair_to_natural(h0, h1, &hours) && pair_to_natural(m0, m1, &minutes)
return pair_to_natural(h, &hours) && pair_to_natural(m, &minutes)
&& minutes < 60 && hours <= UINT32_MAX / 60 - minutes
? (*n = hours * 60 + minutes, 1) : 0;
}
/** `h0` "1" `h1` "." `m0` "5" `m1` -> 90 `n` @return Valid. */
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_decimal_hours_to_minutes(struct pair h, struct pair m,
uint32_t *const n) {
uint32_t hours, minutes;
/* fixme: more precision? */
return pair_to_natural(h0, h1, &hours) && pair_to_natural(m0, m1, &minutes)
return pair_to_natural(h, &hours) && pair_to_natural(m, &minutes)
&& minutes <= 9 && hours <= UINT32_MAX / 60 - minutes * 6
? (*n = hours * 60 + minutes * 6, 1) : 0;
}
@@ -109,12 +108,12 @@ no:
@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) {
int pair_to_date(const unsigned 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');
assert(d);
while(a[0] >= '0' && a[0] <= '9') {
year = year * 10 + (unsigned)(a[0] - '0');
if(year > 0x7FFFFF) return errno = ERANGE, 0; /* 23 bits */
a++;
}
@@ -128,17 +127,16 @@ int pair_to_date(const char *a, union date32 *const d) {
return *d = temp, 1;
}
int pair_to_cents(const char *a, const char *b, int64_t *const cents) {
int pair_to_cents(struct pair p, int64_t *const cents) {
uint64_t d, c;
int is_negative;
assert(a && a < b && cents);
if(a[0] == '-') is_negative = 1, a++, assert(a < b);
else is_negative = 0;
if(a + 2 < b && b[-3] == '.') { /* dollars.cents */
if(!pair_to_64(a, b - 3, &d)) return 0;
c = (uint64_t)(b[-2] - '0') * 10 + (uint64_t)(b[-1] - '0');
assert(p.a < p.b && cents);
if(p.a[0] == '-') is_negative = 1, p.a++; else is_negative = 0;
if(p.a + 2 < p.b && p.b[-3] == '.') { /* dollars.cents */
if(!pair_to_64(pair(p.a, p.b - 3), &d)) return 0;
c = (uint64_t)(p.b[-2] - '0') * 10 + (uint64_t)(p.b[-1] - '0');
} else { /* dollars */
if(!pair_to_64(a, b, &d)) return 0;
if(!pair_to_64(pair(p.a, p.b), &d)) return 0;
c = 0;
}
assert(-INT64_MAX >= INT64_MIN);

View File

@@ -5,17 +5,15 @@
struct pair { const char *a, *b; };
struct pair pair(const char *const a, const char *const b);
int pair_to_natural(const char *, const char *, uint32_t *);
int pair_colon_to_minutes(const char *, const char *,
const char *, const char *, uint32_t *);
int pair_hours_to_minutes(const char *h0, const char *const h1,
const char *m0, const char *const m1, uint32_t *const n);
struct pair pair(const char *a, const char *b);
int pair_to_natural(const struct pair, uint32_t *);
int pair_colon_to_minutes(struct pair h, struct pair m, uint32_t *);
int pair_decimal_hours_to_minutes(struct pair h, struct pair m, 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 *, union date32 *);
int pair_to_cents(const char *, const char *, int64_t *);
int pair_to_date(const unsigned char *a, union date32 *);
int pair_to_cents(struct pair p, int64_t *);
uint32_t pair_djb2(struct pair);
/* Supporting pair -> size_t for looking up in arrays. */

View File

@@ -33,6 +33,10 @@ static void pair_to_string(const struct pair *const p,
*y = '\0';
}
static struct pair pair_u(const unsigned char *const a,
const unsigned char *const b)
{ return pair((const char *)a, (const char *)b); }
static void linepair_to_string(const union line64 line,
const struct pair *const pair,
char (*const a)[12]) { (void)pair; date32_to_string(line.date, a); }
@@ -164,16 +168,19 @@ static int kjv_compare(const union line64 a, const union line64 b)
/*!conditions:re2c*/
/*!flags:utf-8*/
static int scan_day(struct scan *const scan, union date32 date,
const char *const buffer) {
const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *yyt3, *s0, *s1, *t0, *t1;
const unsigned char *const buffer_u = (const unsigned char *)buffer,
*YYCURSOR, *YYMARKER, *yyt1, *yyt2, *yyt3,
*lastnl = buffer_u, *s0, *s1, *t0, *t1;
enum YYCONDTYPE condition = yycline;
/* All '\n' might overflow on last, but it wouldn't matter because there's
no content. */
size_t line = 1;
char datestr[12] = {0};
const char *fail = "perhaps a bat?", *lastnl = buffer;
const char *fail = "perhaps a bat?";
struct {
enum YYCONDTYPE future;
union {
@@ -189,11 +196,11 @@ static int scan_day(struct scan *const scan, union date32 date,
} kjv = { Revelation, 0, 0, 0 };
assert(scan && date.u32 && buffer);
YYCURSOR = YYMARKER = yyt1 = buffer;
YYCURSOR = YYMARKER = yyt1 = buffer_u;
date32_to_string(date, &datestr);
/*!re2c /**/
re2c:define:YYCTYPE = char;
re2c:define:YYCTYPE = "unsigned char";
re2c:yyfill:enable = 0;
re2c:define:YYGETCONDITION = "condition";
re2c:define:YYSETCONDITION = "condition = @@;";
@@ -215,7 +222,8 @@ static int scan_day(struct scan *const scan, union date32 date,
// label except start "()"; used in location
parlabel = (parchar glyph*) (ws+ glyph+)*;
keyword = [A-Za-z0-9][A-Za-z0-9_-]*;
//keyword = [A-Za-z0-9][A-Za-z0-9_-]*;
keyword = [A-Za-z0-9_-é]+;
uint = [0-9]+;
natural = [1-9][0-9]*;
@@ -225,9 +233,9 @@ static int scan_day(struct scan *const scan, union date32 date,
airport = [A-Z0-9]{4,4};
moneyamount = "-"? [0-9]+ ("." [0-9][0-9])?; // fixme?
kjvlookat = ws* natural ":" natural [ab]? ("-" natural [ab]?)? ws+ "--" ws+;
first = ("I" | "1") " "?;
second = ("II" | "2") " "?;
third = ("III" | "3") " "?;
first = ("I" | "1" | "") " "?;
second = ("II" | "2" | "") " "?;
third = ("III" | "3" | "") " "?;
*/
for( ; ; ) {
/*!re2c /**/
@@ -291,7 +299,7 @@ static int scan_day(struct scan *const scan, union date32 date,
size_t *pi;
struct kvpair *doc;
if(!(doc = kvpair_array_new(&scan->documents.array))) goto catch;
doc->key.a = s0, doc->key.b = s1;
doc->key.a = (const char *)s0, doc->key.b = (const char *)s1;
doc->value.a = 0, doc->value.b = 0;
input.future = yycnewline, input.pair = &doc->value;
switch(linemap_tree_bulk_assign(&scan->documents.dates, key, &pi)) {
@@ -333,7 +341,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new contact <<%.*s>>.\n",
@@ -349,7 +357,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new book <<%.*s>>.\n",
@@ -365,7 +373,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new tv <<%.*s>>.\n",
@@ -381,7 +389,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new movie <<%.*s>>.\n",
@@ -397,7 +405,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new idea <<%.*s>>.\n",
@@ -413,7 +421,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new vaccine <<%.*s>>.\n",
@@ -429,7 +437,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new medication <<%.*s>>.\n",
@@ -445,7 +453,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new lab <<%.*s>>.\n",
@@ -461,7 +469,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value = (struct money){0, CAD};
input.future = yycnewline, input.money = &pair->value;
fprintf(stderr, "%s:%zu: new tax <<%.*s>>.\n",
@@ -477,7 +485,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value = (struct money){0, CAD};
input.future = yycline, input.money = &pair->value;
fprintf(stderr, "%s:%zu: new income <<%.*s>>.\n",
@@ -493,7 +501,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new mail <<%.*s>>.\n",
@@ -509,7 +517,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
pair->key.a = s0, pair->key.b = s1;
pair->key = pair_u(s0, s1);
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new couch <<%.*s>>.\n",
@@ -525,7 +533,7 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
if(!pair_to_date(s0, &pair->key)) goto catch;
if(!pair_to_date(s0, &pair->key)) goto catch; /* hmm */
pair->value.a = pair->value.b = 0;
input.future = yycnewline, input.pair = &pair->value;
fprintf(stderr, "%s:%zu: new from.\n", datestr, line);
@@ -534,7 +542,7 @@ static int scan_day(struct scan *const scan, union date32 date,
<place> * { fail = "place unrecognized"; goto catch; }
<place> @s0 parlabel @s1 / "\n" => skip { also_place: {
const struct pair keyword = pair(s0, s1);
const struct pair keyword = pair_u(s0, s1);
const union line64 key = { { (uint32_t)line, date } };
size_t i, *pi;
/*fprintf(stderr, "map: <<%.*s>> out of %s\n", (int)(s1 - s0), s0,
@@ -550,8 +558,8 @@ static int scan_day(struct scan *const scan, union date32 date,
} continue; }
<place> "(" @t0 decimal "," @t1 decimal ")"
ws+ @s0 parlabel @s1 / "\n" => skip {
const struct pair keyword = pair(s0, s1);
const double x = strtod(t0, 0), y = strtod(t1, 0); /* Safe? */
const struct pair keyword = pair_u(s0, s1);
const double x = strtod(keyword.a, 0), y = strtod(keyword.b, 0);
size_t *idx;
struct place *place;
switch(pair_map_table_assign(&scan->places.map, keyword, &idx)) {
@@ -561,7 +569,7 @@ static int scan_day(struct scan *const scan, union date32 date,
}
if(!(place = place_array_new(&scan->places.array))) goto catch;
*idx = (size_t)(place - scan->places.array.data);
place->name.a = s0, place->name.b = s1;
place->name = keyword;
place->x = x, place->y = y;
fprintf(stderr,
"%s:%zu: new place: <<%.*s>> at (%f,%f) stored at %zu.\n",
@@ -572,7 +580,8 @@ static int scan_day(struct scan *const scan, union date32 date,
<place> "(" @t0 decimal "," @t1 decimal ")" / "\n" => skip {
size_t *idx;
struct place *place;
const double x = strtod(t0, 0), y = strtod(t1, 0); /* Safe? */
const struct pair t = pair_u(t0, t1);
const double x = strtod(t.a, 0), y = strtod(t.b, 0); /* Safe? */
const union line64 key = { { (uint32_t)line, date } };
if(!(place = place_array_new(&scan->places.array))) goto catch;
place->name.a = place->name.b = 0;
@@ -589,7 +598,7 @@ static int scan_day(struct scan *const scan, union date32 date,
<source> * { fail = "source unrecognized"; goto catch; }
<source> @s0 keyword @s1 / "\n" => skip { also_source: {
const struct pair keyword = pair(s0, s1);
const struct pair keyword = pair_u(s0, s1);
const union line64 key = { { (uint32_t)line, date } };
size_t i, *pi;
if(!(i = pair_map_table_get(&scan->sources.map, keyword)))
@@ -603,7 +612,7 @@ static int scan_day(struct scan *const scan, union date32 date,
} continue; }
/* New source. */
<source> @s0 keyword @s1 ":" => input_text {
struct pair keyword = pair(s0, s1);
struct pair keyword = pair_u(s0, s1);
size_t *idx;
struct kvpair *source;
switch(pair_map_table_assign(&scan->sources.map, keyword, &idx)) {
@@ -613,7 +622,7 @@ static int scan_day(struct scan *const scan, union date32 date,
}
if(!(source = kvpair_array_new(&scan->sources.array))) goto catch;
*idx = (size_t)(source - scan->sources.array.data);
source->key.a = s0, source->key.b = s1;
source->key = keyword;
source->value.a = 0, source->value.b = 0;
input.future = yycnewline, input.pair = &source->value;
fprintf(stderr, "%s:%zu: new source <<%.*s>> stored at %zu.\n",
@@ -626,7 +635,7 @@ static int scan_day(struct scan *const scan, union date32 date,
/* 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 { new_score: {
const struct pair keyword = pair(s0, s1);
const struct pair keyword = pair_u(s0, s1);
const union line64 key = { { (uint32_t)line, date } };
size_t idx, *pidx;
if(!(idx = pair_map_table_get(&scan->scores.map, keyword)))
@@ -645,10 +654,10 @@ static int scan_day(struct scan *const scan, union date32 date,
/* New score. */
<score> @s0 keyword @s1 ":" => score_name {
size_t *idx;
const struct pair keyword = pair_u(s0, s1);
assert(!new_score);
/* Create a new mapping from dateline to scores array. */
switch(pair_map_table_assign(&scan->scores.map,
pair(s0, s1), &idx)) {
switch(pair_map_table_assign(&scan->scores.map, keyword, &idx)) {
case TABLE_PRESENT: errno = EDOM; fail = "new keyword already used";
case TABLE_ERROR: goto catch; /* _Sic_. */
case TABLE_ABSENT: *idx = 0; break;
@@ -657,7 +666,7 @@ static int scan_day(struct scan *const scan, union date32 date,
if(!(new_score = score_array_new(&scan->scores.array))) goto catch;
*idx = (size_t)(new_score - scan->scores.array.data); /* Offset. */
/*struct pair key, name; union date32 date, last; unsigned edges;*/
new_score->key.a = s0, new_score->key.b = s1;
new_score->key = keyword;
new_score->name.a = 0, new_score->name.b = 0;
new_score->date.u32 = new_score->last.u32 = 0;
new_score->edges = 0, new_score->score = 0;
@@ -668,7 +677,7 @@ static int scan_day(struct scan *const scan, union date32 date,
<score_name> * { fail = "name unrecognized"; goto catch; }
<score_name> ws* @s0 semilabel @s1 ";" => score_date {
assert(new_score);
new_score->name.a = s0, new_score->name.b = s1;
new_score->name = pair_u(s0, s1);
continue;
}
<score_date> * { fail = "date unrecognized"; goto catch; }
@@ -679,8 +688,9 @@ static int scan_day(struct scan *const scan, union date32 date,
}
<score_edges> * { fail = "edges unrecognized"; goto catch; }
<score_edges> ws* "~"? @s0 uint @s1 / "\n" => skip {
const struct pair s = pair_u(s0, s1);
assert(new_score);
if(!pair_to_natural(s0, s1, &new_score->edges)) goto catch;
if(!pair_to_natural(s, &new_score->edges)) goto catch;
new_score = 0; /* Done. */
continue;
}
@@ -696,15 +706,15 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
new_glider->type.a = s0, new_glider->type.b = s1;
new_glider->type = pair_u(s0, s1);
continue;
}
<glider_reg> * { fail = "glider reg"; goto catch; }
<glider_reg> ws* @s0 semilabel @s1 ";" => glider_launch
{ new_glider->reg.a = s0, new_glider->reg.b = s1; continue; }
{ new_glider->reg = pair_u(s0, s1); continue; }
<glider_launch> * { fail = "glider launch"; goto catch; }
<glider_launch> ws* @s0 airport @s1 ";" => glider_how {
new_glider->launch.a = s0, new_glider->launch.b = s1;
new_glider->launch = pair_u(s0, s1);
fprintf(stderr, "%s:%zu: glider <<%.*s>> at <<%.*s>>\n",
datestr, line, (int)(new_glider->reg.b - new_glider->reg.a),
new_glider->reg.a, (int)(s1 - s0), s0);
@@ -720,39 +730,47 @@ static int scan_day(struct scan *const scan, union date32 date,
continue;
}
<glider_height> * { fail = "glider height"; goto catch; }
<glider_height> ws* @s0 natural @s1 "';" => glider_landing
{ if(!pair_to_natural(s0, s1, &new_glider->height_ft)); continue; }
<glider_height> ws* @s0 natural @s1 "';" => glider_landing {
const struct pair s = pair_u(s0, s1);
if(!pair_to_natural(s, &new_glider->height_ft));
continue;
}
<glider_landing> * { fail = "glider landing"; goto catch; }
<glider_landing> ws* @s0 airport @s1 ";" => glider_pilot
{ new_glider->landing.a = s0, new_glider->landing.b = s1; continue;}
{ new_glider->landing = pair_u(s0, s1); continue;}
<glider_pilot> * { fail = "glider pilot time"; goto catch; }
<glider_pilot> ws* ";" => glider_dual /* not PIC */
{ new_glider->pilot_min = 0; continue; }
<glider_pilot> ws* @s0 natural? @s1 ":" @t0 minutes @t1 ws* ";"
=> glider_dual { if(!pair_colon_to_minutes(s0, s1, t0, t1,
=> glider_dual {
if(!pair_colon_to_minutes(pair_u(s0, s1), pair_u(t0, t1),
&new_glider->pilot_min)) { fail = "glider pilot time"; goto catch; }
continue; }
<glider_dual> * { fail = "glider dual time"; goto catch; }
<glider_dual> ws* ";" => glider_instr
{ new_glider->dual_min = 0; continue; }
<glider_dual> ws* @s0 natural? @s1 ":" @t0 minutes @t1 ws* ";"
=> glider_instr { if(!pair_colon_to_minutes(s0, s1, t0, t1,
=> glider_instr {
if(!pair_colon_to_minutes(pair_u(s0, s1), pair_u(t0, t1),
&new_glider->dual_min)) { fail = "glider dual time"; goto catch; }
continue; }
continue;
}
<glider_instr> * { fail = "glider instr time"; goto catch; }
<glider_instr> ws* ";" => glider_remarks
{ new_glider->instr_min = 0; continue; }
<glider_instr> ws* @s0 natural? @s1 ":" @t0 minutes @t1 ws* ";"
=> glider_remarks { if(!pair_hours_to_minutes(s0, s1, t0, t1,
=> glider_remarks {
if(!pair_decimal_hours_to_minutes(pair_u(s0, s1), pair_u(t0, t1),
&new_glider->instr_min)) { fail = "glider instr time"; goto catch; }
continue; }
continue;
}
<glider_remarks> * { fail = "glider remarks"; goto catch; }
<glider_remarks> "\n" @s1 => line
{ new_glider->remarks.a = new_glider->remarks.b = 0;
new_glider = 0; line++; lastnl = s1; continue; }
<glider_remarks> ws* @s0 anylabel @s1 "\n" @t1 => line
{ new_glider->remarks.a = s0, new_glider->remarks.b = s1;
new_glider = 0; line++; lastnl = t1; continue; }
{ new_glider->remarks = pair_u(s0, s1);
new_glider = 0; line++; lastnl = t1; continue; }
/* type; registration; launch -- landing; pic; sic;
@@ -766,17 +784,17 @@ static int scan_day(struct scan *const scan, union date32 date,
case TREE_ERROR: goto catch;
case TREE_ABSENT: break;
}
new_flight->type.a = s0, new_flight->type.b = s1;
new_flight->type = pair_u(s0, s1);
continue;
}
<flight_reg> * { fail = "flight reg"; goto catch; }
<flight_reg> ws* @s0 semilabel @s1 ";" => flight_airports
{ new_flight->reg.a = s0, new_flight->reg.b = s1; continue; }
{ new_flight->reg = pair_u(s0, s1); continue; }
<flight_airports> * { fail = "flight airports"; goto catch; }
<flight_airports> ws* @s0 airport @s1 ws* "--"
ws* @t0 airport @t1 ws* ";" => flight_pic {
new_flight->launch.a = s0, new_flight->launch.b = s1;
new_flight->landing.a = t0, new_flight->landing.b = t1;
new_flight->launch = pair_u(s0, s1);
new_flight->landing = pair_u(t0, t1);
fprintf(stderr, "%s:%zu: flight <<%.*s>> at <<%.*s>>\n",
datestr, line, (int)(new_flight->reg.b - new_flight->reg.a),
new_flight->reg.a, (int)(s1 - s0), s0);
@@ -784,38 +802,42 @@ static int scan_day(struct scan *const scan, union date32 date,
}
<flight_pic> * { fail = "flight pic"; goto catch; }
<flight_pic> ws* @s0 semilabel @s1 ";" => flight_sic
{ new_flight->pilot.a = s0, new_flight->pilot.b = s1; continue; }
{ new_flight->pilot = pair_u(s0, s1); continue; }
<flight_sic> * { fail = "flight sic"; goto catch; }
<flight_sic> ws* ";" => flight_dual
{ new_flight->copilot.a = new_flight->copilot.b = 0; continue; }
<flight_sic> ws* @s0 semilabel @s1 ";" => flight_dual
{ new_flight->copilot.a = s0, new_flight->copilot.b = s1; continue; }
{ new_flight->copilot = pair_u(s0, s1); continue; }
<flight_dual> * { fail = "flight dual time"; goto catch; }
<flight_dual> ws* ";" => flight_pilot
{ new_flight->dual_min = 0; continue; }
<flight_dual> ws* @s0 [0-9]* @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_pilot { if(!pair_hours_to_minutes(s0, s1, t0, t1,
=> flight_pilot {
if(!pair_decimal_hours_to_minutes(pair_u(s0, s1), pair_u(t0, t1),
&new_flight->dual_min)) { fail = "flight dual time"; goto catch; }
continue; }
<flight_pilot> * { fail = "flight pilot time"; goto catch; }
<flight_pilot> ws* ";" => flight_ifrsim
{ new_flight->pilot_min = 0; continue; }
<flight_pilot> ws* @s0 [0-9]* @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_ifrsim { if(!pair_hours_to_minutes(s0, s1, t0, t1,
=> flight_ifrsim {
if(!pair_decimal_hours_to_minutes(pair_u(s0, s1), pair_u(t0, t1),
&new_flight->pilot_min)) { fail = "flight pilot time";
goto catch; } continue; }
<flight_ifrsim> * { fail = "flight simulated ifr time"; goto catch; }
<flight_ifrsim> ws* ";" => flight_ifr
{ new_flight->ifrsim_min = 0; continue; }
<flight_ifrsim> ws* @s0 [0-9]* @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_ifr { if(!pair_hours_to_minutes(s0, s1, t0, t1,
=> flight_ifr {
if(!pair_decimal_hours_to_minutes(pair_u(s0, s1), pair_u(t0, t1),
&new_flight->ifrsim_min)) { fail = "flight simulated ifr time";
goto catch; } continue; }
<flight_ifr> * { fail = "flight ifr time"; goto catch; }
<flight_ifr> ws* ";" => flight_remarks
{ new_flight->ifr_min = 0; continue; }
<flight_ifr> ws* @s0 [0-9]* @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_remarks { if(!pair_hours_to_minutes(s0, s1, t0, t1,
=> flight_remarks {
if(!pair_decimal_hours_to_minutes(pair_u(s0, s1), pair_u(t0, t1),
&new_flight->ifr_min)) { fail = "flight ifr time"; goto catch; }
continue; }
<flight_remarks> * { fail = "flight remarks"; goto catch; }
@@ -823,7 +845,7 @@ static int scan_day(struct scan *const scan, union date32 date,
{ new_flight->remarks.a = new_flight->remarks.b = 0;
new_flight = 0; line++; lastnl = s1; continue; }
<flight_remarks> ws* @s0 anylabel @s1 "\n" @t1 => line
{ new_flight->remarks.a = s0, new_flight->remarks.b = s1;
{ new_flight->remarks = pair_u(s0, s1);
new_flight = 0; line++; lastnl = t1; continue; }
@@ -901,19 +923,19 @@ static int scan_day(struct scan *const scan, union date32 date,
<kjvbook> " " @s0 natural @s1 ":" @t0 natural @t1 [ab]? {
if(kjv.chapter || kjv.verse || kjv.verse_end)
{ fail = "kjv reference"; goto catch; }
if(!pair_to_natural(s0, s1, &kjv.chapter)
|| !pair_to_natural(t0, t1, &kjv.verse))
if(!pair_to_natural(pair_u(s0, s1), &kjv.chapter)
|| !pair_to_natural(pair_u(t0, t1), &kjv.verse))
{ fail = "kjv reference numerical error"; goto catch; }
continue;
}
<kjvbook> "-" @s0 natural @s1 [ab]? { /* Verse range. */
<kjvbook> "" @s0 natural @s1 [ab]? { /* Verse range. */
if(!kjv.chapter || !kjv.verse || kjv.verse_end)
{ fail = "kjv range unrecognized"; goto catch; }
if(!pair_to_natural(s0, s1, &kjv.verse_end))
if(!pair_to_natural(pair_u(s0, s1), &kjv.verse_end))
{ fail = "kjv range numerical error"; goto catch; }
continue;
}
<kjvbook> " -- " => skip {
<kjvbook> " " => skip {
if(!kjv.chapter || !kjv.verse)
{ fail = "kjv missing information"; goto catch; }
if(kjv.verse_end && kjv.verse_end <= kjv.verse)
@@ -945,13 +967,14 @@ static int scan_day(struct scan *const scan, union date32 date,
<input_text, input_text_multi> * { fail = "text input"; goto catch; }
<input_text> ws { continue; }
<input_text> "<<\n" @s0 => input_text_multi { // multi-line
input.pair->a = s0;
const struct pair s = pair_u(s0, s1);
input.pair->a = s.a;
line++; lastnl = s0;
continue;
}
<input_text> @s0 anylabel? @s1 "\n" @t0 => line { // one line; last one
/*fprintf(stderr, "text: <<%.*s>>\n", (int)(s1 - s0), s0);*/
input.pair->a = s0, input.pair->b = s1;
*input.pair = pair_u(s0, s1);
if(input.future != yycnewline)
{ fail = "use <<text>>"; goto catch; }
line++; lastnl = t0;
@@ -964,7 +987,8 @@ static int scan_day(struct scan *const scan, union date32 date,
<input_text_multi> @s1 ">>" / [^>] /*future*/ {
/*fprintf(stderr, "text: <<\n%.*s>>\n",
(int)(s1 - input.pair->a), input.pair->a);*/
input.pair->b = s1;
const struct pair s = pair_u(s0, s1);
input.pair->b = s.b;
condition = input.future;
continue;
}
@@ -973,7 +997,7 @@ static int scan_day(struct scan *const scan, union date32 date,
{ fail = "money input"; goto catch; }
<input_money> ws { continue; }
<input_money> @s0 moneyamount @s1 => input_money_currency {
if(!pair_to_cents(s0, s1, &input.money->cents)) goto catch;
if(!pair_to_cents(pair_u(s0, s1), &input.money->cents)) goto catch;
printf("input_money: amount %" PRId64 "\n", input.money->cents);
continue;
}
@@ -988,8 +1012,12 @@ static int scan_day(struct scan *const scan, union date32 date,
catch:
if(!errno) errno = EILSEQ;
date32_to_string(date, &datestr);
if(s1 = strchr(lastnl, '\n')) {
fprintf(stderr, "%.*s\n", (int)(s1 - lastnl), lastnl);
{
const char *const lastnl_s = (const char *)lastnl;
char *result;
if(result = strchr(lastnl_s, '\n')) {
fprintf(stderr, "%.*s\n", (int)(result - lastnl_s), lastnl_s);
}
}
fprintf(stderr,
"%s:%zu fail: %s" /*" condition %d"*/ ".\n",