interpret/src/flights.re.c

240 lines
9.6 KiB
C

/** @license 2023 Neil Edelman, distributed under the terms of the
[MIT License](https://opensource.org/licenses/MIT).
@std C11 */
#include "../src/flights.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
static void flight_to_string(const union line64 line, const struct flight *u,
char (*const a)[12]) { (void)u; date32_to_string(line.date, a); }
static int flight_compare(const union line64 a, const union line64 b)
{ return a.u64 > b.u64; }
#define TREE_NAME flight
#define TREE_KEY union line64
#define TREE_VALUE struct flight
#define TREE_COMPARE
#define TREE_TO_STRING
#define TREE_BODY
#include "../src/tree.h"
/*!conditions:re2c*/
static int scan(struct flight_tree *const f,
union date32 date, const char *const text) {
const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *s0, *s1, *t0, *t1;
enum YYCONDTYPE condition = yycline;
size_t line = 1;
char datestr[12] = {0};
const char *why = "unexpected";
struct flight *flight = 0;
assert(f && text);
YYCURSOR = YYMARKER = yyt1 = text;
/*!re2c /**/
re2c:define:YYCTYPE = char;
re2c:yyfill:enable = 0;
re2c:define:YYGETCONDITION = "condition";
re2c:define:YYSETCONDITION = "condition = @@;";
re2c:define:YYGETCONDITION:naked = 1;
re2c:define:YYSETCONDITION:naked = 1;
ws = [ \t];
glyph = [^\x00-\x20\x7f]; // [^\x00\n\t ] + all weird
semitext = glyph \ ";";
natural = [1-9][0-9]*;
minutes = [0-5][0-9];
zero_natural = natural | "0";
airport = [A-Z0-9]{4,4};
*/
for( ; ; ) { /*!re2c /**/
/* Default ignore. */
<skip> [^\n\x00] { continue; }
<skip> "\x00" { why = "no newline at end of file"; goto catch; }
<line> "\x00" { return 1; }
<line, skip> "\n" => line { line++; continue; }
<line> * :=> skip
/* Except this . . . */
<line> "[glider]" :=> glider_type
/* type, reg, launch, how, height, landing, pilot, dual, instr, remarks
eg, [glider] 2-33A; C-GCLK; CYQQ; A; 2000'; CYQQ; ;:13;; Peters D1 */
<glider_type> * { why = "type unrecognized"; goto catch; }
<glider_reg> * { why = "reg unrecognized"; goto catch; }
<glider_launch> * { why = "launch unrecognized"; goto catch; }
<glider_how> * { why = "how unrecognized"; goto catch; }
<glider_height> * { why = "height unrecognized"; goto catch; }
<glider_landing> * { why = "landing unrecognized"; goto catch; }
<glider_pilot> * { why = "pilot unrecognized"; goto catch; }
<glider_dual> * { why = "dual unrecognized"; goto catch; }
<glider_instr> * { why = "instr unrecognized"; goto catch; }
<glider_remarks> * { why = "remarks unrecognized"; goto catch; }
<glider_type> ws* @s0 semitext+ @s1 ws* ";" => glider_reg {
const union line64 key
= {{ (uint32_t)line, {{ date.day, date.month, date.year }} }};
assert(!flight);
if(line > UINT32_MAX) { why = "line overflow"; goto catch; }
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;
}
flight->glider.type.a = s0, flight->glider.type.b = s1;
continue;
}
<glider_reg> ws* @s0 semitext+ @s1 ws* ";" => glider_launch
{ flight->glider.reg.a = s0, flight->glider.reg.b = s1; continue; }
<glider_launch> ws* @s0 airport @s1 ws* ";" => glider_how
{ flight->glider.launch.a = s0, flight->glider.launch.b = s1;
continue; }
<glider_how> ws* @s0 [MWA] ws* ";" => glider_height {
switch(*s0) {
case 'M': flight->glider.how = MotorCarTow; break;
case 'W': flight->glider.how = Winch; break;
case 'A': flight->glider.how = AeroTow; break;
default: assert(0); break;
}
continue;
}
<glider_height> ws* @s0 natural @s1 "'" ws* ";" => glider_landing
{ if(!pair_to_natural(s0, s1, &flight->glider.height_ft));
continue; }
<glider_landing> ws* @s0 airport @s1 ws* ";" => glider_pilot
{ flight->glider.landing.a = s0, flight->glider.landing.b = s1;
continue; }
<glider_pilot> ws* ";" => glider_dual /* not PIC */
{ flight->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,
&flight->glider.pilot_min)) { why = "pilot time"; goto catch; }
continue; }
<glider_dual> ws* ";" => glider_instr
{ flight->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,
&flight->glider.dual_min)) { why = "dual time"; goto catch; }
continue; }
<glider_instr> ws* ";" => glider_remarks
{ flight->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,
&flight->glider.instr_min)) { why = "instr time"; goto catch; }
continue; }
<glider_remarks> ws* "\n" => line
{ flight->glider.remarks.a = flight->glider.remarks.b = 0;
flight = 0; line++; continue; }
<glider_remarks> ws* @s0 glyph+ (ws+ glyph+)* @s1 "\n" => line
{ flight->glider.remarks.a = s0, flight->glider.remarks.b = s1;
flight = 0; line++; continue; }
/* And this . . . */
<line> "[flight]" :=> flight_type
/* type; registration; launch -- landing; pic; sic;
single engine day dual; pilot; instrument simulated; actual; remarks */
<flight_type> * { why = "type unrecognized"; goto catch; }
<flight_reg> * { why = "reg unrecognized"; goto catch; }
<flight_airports> * { why = "airports unrecognized"; goto catch; }
<flight_pic> * { why = "pic unrecognized"; goto catch; }
<flight_sic> * { why = "sic unrecognized"; goto catch; }
<flight_dual> * { why = "dual time unrecognized"; goto catch; }
<flight_pilot> * { why = "pilot time unrecognized"; goto catch; }
<flight_ifrsim> * { why = "simulated ifr time unrecognized";
goto catch; }
<flight_ifr> * { why = "ifr time unrecognized"; goto catch; }
<flight_remarks> * { why = "remarks unrecognized"; goto catch; }
<flight_type> ws* @s0 semitext+ @s1 ws* ";" => flight_reg {
const union line64 key
= {{ (uint32_t)line, {{ date.day, date.month, date.year }} }};
assert(!flight);
if(line > UINT32_MAX) { why = "line overflow"; goto catch; }
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;
}
flight->power.type.a = s0, flight->power.type.b = s1;
continue;
}
<flight_reg> ws* @s0 semitext+ @s1 ws* ";" => flight_airports
{ flight->power.reg.a = s0, flight->power.reg.b = s1; continue; }
<flight_airports> ws* @s0 airport @s1 ws* "--"
ws* @t0 airport @t1 ws* ";" => flight_pic {
flight->power.launch.a = s0, flight->power.launch.b = s1;
flight->power.landing.a = t0, flight->power.landing.b = t1;
continue;
}
<flight_pic> ws* @s0 semitext+ (ws+ semitext+)* @s1 /* ws*? */";"
=> flight_sic { flight->power.pilot.a = s0,
flight->power.pilot.b = s1; continue; }
<flight_sic> ws* ";" => flight_dual
{ flight->power.copilot.a = flight->power.copilot.b = 0; continue; }
<flight_sic> ws* @s0 semitext+ (ws+ semitext+)* @s1 ";"
=> flight_dual { flight->power.copilot.a = s0,
flight->power.copilot.b = s1; continue; }
<flight_dual> ws* ";" => flight_pilot
{ flight->power.dual_min = 0; continue; }
<flight_dual> ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_pilot { if(!pair_hours_to_minutes(s0, s1, t0, t1,
&flight->power.dual_min)) { why = "dual time"; goto catch; }
continue; }
<flight_pilot> ws* ";" => flight_ifrsim
{ flight->power.pilot_min = 0; continue; }
<flight_pilot> ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_ifrsim { if(!pair_hours_to_minutes(s0, s1, t0, t1,
&flight->power.pilot_min)) { why = "pilot time"; goto catch; }
continue; }
<flight_ifrsim> ws* ";" => flight_ifr
{ flight->power.ifrsim_min = 0; continue; }
<flight_ifrsim> ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_ifr { if(!pair_hours_to_minutes(s0, s1, t0, t1,
&flight->power.ifrsim_min)) { why = "simulated ifr time";
goto catch; } continue; }
<flight_ifr> ws* ";" => flight_remarks
{ flight->power.ifr_min = 0; continue; }
<flight_ifr> ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";"
=> flight_remarks { if(!pair_hours_to_minutes(s0, s1, t0, t1,
&flight->power.ifr_min)) { why = "pilot time"; goto catch; }
continue; }
<flight_remarks> ws* "\n" => line
{ flight->power.remarks.a = flight->power.remarks.b = 0;
flight = 0; line++; continue; }
<flight_remarks> ws* @s0 glyph+ (ws+ glyph+)* @s1 "\n" => line
{ flight->power.remarks.a = s0, flight->power.remarks.b = s1;
flight = 0; line++; continue; }
*/ }
assert(0); /* Never gets here. */
catch:
if(!errno) errno = EILSEQ;
date32_to_string(date, &datestr);
fprintf(stderr, "%s line %zu: %s.\n", datestr, line, why);
return 0;
}
void flights_(struct flight_tree *const f) { flight_tree_(f); }
struct flight_tree flights(struct journal *const j) {
struct flight_tree f = flight_tree();
struct journal_iterator it;
union date32 date;
const char *text;
assert(j);
it = journal_iterator(j);
while(journal_next(&it, &date, &text)) if(!scan(&f, date, text)) goto catch;
goto finally;
catch:
flights_(&f);
finally:
return f;
}
const char *flights_to_string(const struct flight_tree *const f)
{ return flight_tree_to_string(f); }
struct flight_tree_iterator flights_iterator(struct flight_tree *const f)
{ return flight_tree_iterator(f); }
int flights_next(struct flight_tree_iterator *const it, union line64 *const k,
const struct flight **const v) {
assert(it && k && v);
if(!flight_tree_next(it)) return 0;
*k = flight_tree_key(it);
*v = flight_tree_value(it);
return 1;
}