cons, allows automation of pop; <!condition>

This commit is contained in:
Neil 2022-02-15 13:56:36 -08:00
parent fb814b7223
commit 3dd4557438
2 changed files with 29 additions and 22 deletions

View File

@ -6,9 +6,10 @@ int lex_looks_like_day(const char *);
#define LEX_SYMBOL \ #define LEX_SYMBOL \
/* Results. */ X(END), X(SYNTAX), X(ILLEGAL), X(NOT_FOUND), \ /* Results. */ X(END), X(SYNTAX), X(ILLEGAL), X(NOT_FOUND), \
/* Text */ X(PARAGRAPH), X(TEXT), \ /* Text. */ X(PARAGRAPH), X(TEXT), \
/* Directive. */ X(SOURCE), X(DEFAULT), X(SIGNIFICANT), X(SCORE), X(MAP), \ /* Edicts. */ X(SOURCE), X(DEFAULT), X(SIGNIFICANT), X(SCORE), X(MAP), \
/* Arguments. */ X(ARG_KEYWORD), X(ARG_DATE), X(ARG_NATURAL), X(ARG_FREEFORM) /* Arguments. */ X(ARG_KEYWORD), X(ARG_DATE), X(ARG_NATURAL), \
X(ARG_FREEFORM)
#define X(n) n #define X(n) n
struct lex { struct lex {

View File

@ -20,7 +20,7 @@ re2c:define:YYCTYPE = char;
int lex_looks_like_year(const char *const a, int *const year) { int lex_looks_like_year(const char *const a, int *const year) {
const char *YYCURSOR = a, *YYMARKER = a, *s0; const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */ /*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt1; (void)yyt2, (void)yyt3;
assert(a && year); assert(a && year);
/*!re2c /*!re2c
@s0 ("-"? [1-9][0-9]* | "0") "\x00" { @s0 ("-"? [1-9][0-9]* | "0") "\x00" {
@ -41,6 +41,7 @@ int lex_looks_like_year(const char *const a, int *const year) {
int lex_looks_like_month(const char *const a) { int lex_looks_like_month(const char *const a) {
const char *YYCURSOR = a, *YYMARKER = a, *s0; const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */ /*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt1, (void)yyt2, (void)yyt3;
assert(a); assert(a);
/*!re2c /*!re2c
@s0 [0-1][0-9] "\x00" { @s0 [0-1][0-9] "\x00" {
@ -54,6 +55,7 @@ int lex_looks_like_month(const char *const a) {
int lex_looks_like_day(const char *const a) { int lex_looks_like_day(const char *const a) {
const char *YYCURSOR = a, *YYMARKER = a, *s0; const char *YYCURSOR = a, *YYMARKER = a, *s0;
/*!stags:re2c format = 'const char *@@;\n'; */ /*!stags:re2c format = 'const char *@@;\n'; */
(void)yyt1, (void)yyt2, (void)yyt3;
assert(a); assert(a);
/*!re2c /*!re2c
@s0 [0-3][0-9] ".txt\x00" { @s0 [0-3][0-9] ".txt\x00" {
@ -67,7 +69,12 @@ int lex_looks_like_day(const char *const a) {
/* This defines `enum condition`. */ /* This defines `enum condition`. */
/*!types:re2c*/ /*!types:re2c*/
#define EXPECT X(KEYWORD), X(DATE), X(FREEFORM) /* "[edict: expect; there; to; be; args]", in this case, expect would be a
stack of `size = 5` `EXPECT_KEYWORD`. This mirrors arguments in `LEX_SYMBOL`
and should also be an `edict_*` in <fn:lex_next> and <fn:expect_pop>. */
#define EXPECT_HEAD X(keyword, KEYWORD) X(date, DATE)
#define EXPECT_CONS Y(freeform, FREEFORM)
#define EXPECT EXPECT_HEAD EXPECT_CONS
/** scanner reads a file and extracts semantic information. Valid to access /** scanner reads a file and extracts semantic information. Valid to access
only while underlying pointers do not change. */ only while underlying pointers do not change. */
@ -79,29 +86,31 @@ static struct scan {
enum condition condition; enum condition condition;
size_t line; size_t line;
int is_ws_expected, is_source; int is_ws_expected, is_source;
#define X(n) EXPECT_ ## n #define X(n, N) EXPECT_ ## N,
/* "[something: expect; there; to; be; args]", in this case, expect would #define Y(n, N) EXPECT_ ## N
be a stack of `size = 5` `EXPECT_KEYWORD`. */
struct { unsigned size; enum { EXPECT } expect[16]; } edict; struct { unsigned size; enum { EXPECT } expect[16]; } edict;
#undef X #undef X
} scan; /* Terrible, gah. */ #undef Y
} scan; /* Not suited for concurrency. Simple. */
/** Resets the buffer to some `buffer`. */
void lex_reset(const char *const buffer) { void lex_reset(const char *const buffer) {
scan.marker = scan.ctx_marker = scan.from = scan.cursor = scan.label scan.marker = scan.ctx_marker = scan.from = scan.cursor = scan.label
= scan.buffer = buffer; = scan.buffer = buffer;
scan.condition = 0; scan.condition = yycline;
scan.line = 1; scan.line = 1;
} }
/** I don't think `re2c` supports branching on variable conditions. /** I don't think `re2c` supports branching on variable conditions.
It does now? */ It does now? */
static void expect_pop(void) { static void expect_pop(void) {
printf("<expect_pop>"); if(!scan.edict.size) { scan.condition = yycedict_end; return; }
if(!scan.edict.size) { printf("allfinished\n"); scan.condition = yycedict_end; return; }
switch(scan.edict.expect[--scan.edict.size]) { switch(scan.edict.expect[--scan.edict.size]) {
case EXPECT_KEYWORD: printf("keyword\n");scan.condition = yycedict_keyword; break; #define X(n, N) case EXPECT_ ## N : scan.condition = yycedict_ ## n; break;
case EXPECT_DATE: printf("date\n");scan.condition = yycedict_date; break; #define Y(n, N) case EXPECT_ ## N : scan.condition = yycedict_ ## n; break;
case EXPECT_FREEFORM: printf("freeform\n");scan.condition = yycedict_freeform; break; EXPECT
#undef X
#undef Y
} }
} }
@ -118,14 +127,10 @@ int lex_next(struct lex *const x) {
re2c:define:YYSETCONDITION:naked = 1; re2c:define:YYSETCONDITION:naked = 1;
*/ */
const char *s0, *s1; const char *s0, *s1;
const size_t prev_line = scan.line;
/*!stags:re2c format = 'const char *@@;\n'; */ /*!stags:re2c format = 'const char *@@;\n'; */
assert(x); assert(x);
if(!scan.buffer) return 0; if(!scan.buffer) return 0;
x->s0 = x->s1 = 0; x->s0 = x->s1 = 0;
x->line = prev_line;
x->ws_before = 0;
x->new_paragraph = 0;
scan: scan:
/*!re2c /*!re2c
end = "\x00"; end = "\x00";
@ -196,16 +201,17 @@ scan:
{ if(!scan.edict.size) return x->symbol = SYNTAX, 0; { if(!scan.edict.size) return x->symbol = SYNTAX, 0;
scan.is_ws_expected = 0, scan.is_source = 0; scan.is_ws_expected = 0, scan.is_source = 0;
expect_pop(); goto scan; } expect_pop(); goto scan; }
<! edict_keyword, edict_date, edict_freeform> { expect_pop(); }
<edict_keyword> ws* @s0 id @s1 ws* ";"? / "]"? <edict_keyword> ws* @s0 id @s1 ws* ";"? / "]"?
{ x->s0 = s0, x->s1 = s1; expect_pop(); { x->s0 = s0, x->s1 = s1;
return x->symbol = ARG_KEYWORD, 1; } return x->symbol = ARG_KEYWORD, 1; }
<edict_date> ws* @s0 date @s1 ws* ";"? / "]"? <edict_date> ws* @s0 date @s1 ws* ";"? / "]"?
{ x->s0 = s0, x->s1 = s1; expect_pop(); { x->s0 = s0, x->s1 = s1;
return x->symbol = ARG_DATE, 1; } return x->symbol = ARG_DATE, 1; }
<edict_freeform> ws* @s0 <edict_freeform> ws* @s0
[^ \t\n\r\v\f;[\]\x00][^\t\n\r\v\f;[\]\x00]*[^ \t\n\r\v\f;[\]\x00]* [^ \t\n\r\v\f;[\]\x00][^\t\n\r\v\f;[\]\x00]*[^ \t\n\r\v\f;[\]\x00]*
@s1 ws* ";"? / "]"? @s1 ws* ";"? / "]"?
{ x->s0 = s0, x->s1 = s1; expect_pop(); { x->s0 = s0, x->s1 = s1;
return x->symbol = ARG_FREEFORM, 1; } return x->symbol = ARG_FREEFORM, 1; }
<edict, edict_end> "]" => text <edict, edict_end> "]" => text
{ if(scan.edict.size) return 0; { if(scan.edict.size) return 0;