From 9c85f86b7e105402b5e5c49c6a94fa4b6c2aa6a6 Mon Sep 17 00:00:00 2001 From: Ulya Trofimovich Date: Tue, 15 Jan 2019 23:45:53 +0000 Subject: [PATCH] Make re2c:eof usable with push-model lexers (-f, --storable-state option). --- re2c/src/codegen/emit_action.cc | 77 ++-- re2c/src/codegen/emit_dfa.cc | 2 +- re2c/src/parse/validate.cc | 6 +- re2c/test/eof/nonblocking_push.fi.c | 619 +++++++++++++++++++++++++++ re2c/test/eof/nonblocking_push.fi.re | 181 ++++++++ 5 files changed, 855 insertions(+), 30 deletions(-) create mode 100644 re2c/test/eof/nonblocking_push.fi.c create mode 100644 re2c/test/eof/nonblocking_push.fi.re diff --git a/re2c/src/codegen/emit_action.cc b/re2c/src/codegen/emit_action.cc index 199fc492..5714b2dd 100644 --- a/re2c/src/codegen/emit_action.cc +++ b/re2c/src/codegen/emit_action.cc @@ -31,8 +31,8 @@ static void emit_accept_binary (Output &o, uint32_t ind, const DFA &dfa, const a static void emit_accept (Output &o, uint32_t ind, const DFA &dfa, const accept_t &acc); static void emit_rule (Output &o, uint32_t ind, const DFA &dfa, size_t rule_idx); static void gen_fintags (Output &o, uint32_t ind, const DFA &dfa, const Rule &rule); -static void gen_goto (code_lines_t &code, const State *from, const State *to, const DFA &dfa, tcid_t tcid, const opt_t *opts, bool skip, bool fill); -static void gen_on_eof (code_lines_t &code, const opt_t *opts, const DFA &dfa, const State *from, const State *to); +static void gen_goto (code_lines_t &, const State *, const State *, const DFA &, tcid_t, const opt_t *, bool, bool, uint32_t); +static void gen_on_eof (code_lines_t &, const opt_t *, const DFA &, const State *, const State *, uint32_t); static bool endstate (const State *s); static void flushln (code_lines_t &code, std::ostringstream &o); @@ -245,13 +245,18 @@ void gen_rescan_label(Output &o, const State *s) if (opts->eof == NOEOF || endstate(s)) return; o.wstring(opts->labelPrefix).wlabel(s->label).ws("_:\n"); + + if (opts->fFlag) { + o.wstring(opts->yyfilllabel).wu32(o.fill_index).ws(":\n"); + ++o.fill_index; + } } void gen_goto_case(Output &o, uint32_t ind, const State *from, const State *to, const DFA &dfa, tcid_t tcid, bool skip, bool fill) { code_lines_t code; - gen_goto(code, from, to, dfa, tcid, o.block().opts, skip, fill); + gen_goto(code, from, to, dfa, tcid, o.block().opts, skip, fill, o.fill_index); const size_t lines = code.size(); if (lines == 1) { @@ -268,7 +273,7 @@ void gen_goto_if(Output &o, uint32_t ind, const State *from, const State *to, const DFA &dfa, tcid_t tcid, bool skip, bool eof) { code_lines_t code; - gen_goto(code, from, to, dfa, tcid, o.block().opts, skip, eof); + gen_goto(code, from, to, dfa, tcid, o.block().opts, skip, eof, o.fill_index); const size_t lines = code.size(); if (lines == 1) { @@ -286,7 +291,7 @@ void gen_goto_plain(Output &o, uint32_t ind, const State *from, const State *to, const DFA &dfa, tcid_t tcid, bool skip, bool eof) { code_lines_t code; - gen_goto(code, from, to, dfa, tcid, o.block().opts, skip, eof); + gen_goto(code, from, to, dfa, tcid, o.block().opts, skip, eof, o.fill_index); const size_t lines = code.size(); for (size_t i = 0; i < lines; ++i) { @@ -295,10 +300,11 @@ void gen_goto_plain(Output &o, uint32_t ind, const State *from, const State *to, } void gen_goto(code_lines_t &code, const State *from, const State *to - , const DFA &dfa, tcid_t tcid, const opt_t *opts, bool skip, bool fill) + , const DFA &dfa, tcid_t tcid, const opt_t *opts, bool skip, bool fill + , uint32_t fillidx) { if (fill) { - gen_on_eof(code, opts, dfa, from, to); + gen_on_eof(code, opts, dfa, from, to, fillidx); } if (skip && !opts->lookahead) { @@ -322,7 +328,7 @@ void gen_goto(code_lines_t &code, const State *from, const State *to } void gen_on_eof(code_lines_t &code, const opt_t *opts, const DFA &dfa - , const State *from, const State *to) + , const State *from, const State *to, uint32_t fillidx) { const State *retry = from->action.type == Action::MOVE ? from->prev : from; const State *fallback = from->rule == Rule::NONE @@ -341,36 +347,51 @@ void gen_on_eof(code_lines_t &code, const opt_t *opts, const DFA &dfa o << ") {"; flushln(code, o); - o << opts->indString << "if (" << opts->fill << " () == 0) " - << "goto " << opts->labelPrefix << retry->label << "_;"; - flushln(code, o); + if (opts->fFlag) { + --fillidx; + std::string s = opts->state_set; + strrreplace(s, opts->state_set_arg, fillidx); + o << opts->indString << s; + if (!opts->state_set_naked) { + o << "(" << fillidx << ");"; + } + flushln(code, o); - if (from->action.type == Action::INITIAL) { - o << opts->indString << "else goto " << opts->labelPrefix << "eof;"; + o << opts->indString << opts->fill << " ();"; flushln(code, o); } - else if (fallback != to) { - code_lines_t tagcode; - gen_settags(tagcode, dfa, falltags, opts); + else { + o << opts->indString << "if (" << opts->fill << " () == 0) " + << "goto " << opts->labelPrefix << retry->label << "_;"; + flushln(code, o); - if (tagcode.empty()) { - o << opts->indString << "else goto " << opts->labelPrefix << fallback->label << ";"; + if (from->action.type == Action::INITIAL) { + o << opts->indString << "else goto " << opts->labelPrefix << "eof;"; flushln(code, o); } - else { - o << opts->indString << "else {"; - flushln(code, o); + else if (fallback != to) { + code_lines_t tagcode; + gen_settags(tagcode, dfa, falltags, opts); - for (uint32_t i = 0; i < tagcode.size(); ++i) { - code.push_back(opts->indString + opts->indString + tagcode[i]); + if (tagcode.empty()) { + o << opts->indString << "else goto " << opts->labelPrefix << fallback->label << ";"; + flushln(code, o); } + else { + o << opts->indString << "else {"; + flushln(code, o); - o << opts->indString << opts->indString - << "goto " << opts->labelPrefix << fallback->label << ";"; - flushln(code, o); + for (uint32_t i = 0; i < tagcode.size(); ++i) { + code.push_back(opts->indString + opts->indString + tagcode[i]); + } - o << opts->indString << "}"; - flushln(code, o); + o << opts->indString << opts->indString + << "goto " << opts->labelPrefix << fallback->label << ";"; + flushln(code, o); + + o << opts->indString << "}"; + flushln(code, o); + } } } diff --git a/re2c/src/codegen/emit_dfa.cc b/re2c/src/codegen/emit_dfa.cc index 3d0bb60c..83584b57 100644 --- a/re2c/src/codegen/emit_dfa.cc +++ b/re2c/src/codegen/emit_dfa.cc @@ -48,7 +48,7 @@ void emit_eof(Output & o, uint32_t ind, const Code *code) { const opt_t *opts = o.block().opts; - if (opts->eof == NOEOF) return; + if (opts->eof == NOEOF || opts->fFlag) return; o.wstring(opts->labelPrefix).ws("eof:\n"); o.wdelay_line_info_input(code->fline, code->fname); diff --git a/re2c/src/parse/validate.cc b/re2c/src/parse/validate.cc index b02d972f..c0709d11 100644 --- a/re2c/src/parse/validate.cc +++ b/re2c/src/parse/validate.cc @@ -46,10 +46,14 @@ void validate_ast(const specs_t &specs, const opt_t *opts) fatal("%sEOF rule found, but 're2c:eof' configuration is not set", incond(i->name).c_str()); } - else if (i->eofs.empty() && opts->eof != NOEOF) { + else if (i->eofs.empty() && opts->eof != NOEOF && !opts->fFlag) { fatal("%s're2c:eof' configuration is set, but no EOF rule found", incond(i->name).c_str()); } + else if (!i->eofs.empty() && opts->fFlag) { + fatal("%sEOF rule is unreachable in push-model lexers", + incond(i->name).c_str()); + } else if (i->eofs.size() > 1) { fatal_l(i->eofs[1]->fline, "EOF rule %sis already defined at line %u", diff --git a/re2c/test/eof/nonblocking_push.fi.c b/re2c/test/eof/nonblocking_push.fi.c new file mode 100644 index 00000000..197cb810 --- /dev/null +++ b/re2c/test/eof/nonblocking_push.fi.c @@ -0,0 +1,619 @@ +/* Generated by re2c */ +#include +#include +#include +#include +#include +#include + +#define YYMAXFILL 19 + +static const size_t SIZE = 4096; + +struct input_t { + char buf[SIZE + YYMAXFILL]; + char *lim; + char *cur; + char *tok; + char *mark; + int state; + unsigned yyaccept; + char yych; + FILE *file; + + input_t(FILE * file) + : buf() + , lim(buf + SIZE) + , cur(lim) + , tok(lim) + , mark(lim) + , state(0) + , yyaccept(0) + , yych(0) + , file(file) + {} + + bool fill() + { + const size_t free = (tok - buf) + SIZE - (lim - buf); + if (free < 1) return false; + const size_t prefix = (tok - buf); + + memmove(buf, tok, buf - tok + SIZE); + lim -= prefix; + cur -= prefix; + tok -= prefix; + mark -= prefix; + size_t to_read = SIZE - (lim - buf); + printf("> Reading input, can take up to %lu bytes\n", to_read); + size_t bytes_read = fread(lim, 1, to_read, file); + lim += bytes_read; + lim[0] = 0; + + // simulate the END packet (can as well send a normal packet) + if (feof(file)) ++lim; + + // quick make a copy of buffer with newlines replaced w/ _ + char b[40]; + snprintf(b, 40, "%s", buf); + for(int i = 0; i < 40; i++) { + if ('\n' == b[i]) { b[i] = '_'; } + } + printf("> Read %lu bytes from input, current buffer: >%.40s<\n", bytes_read, b); + + return true; + } +}; + +enum status_t { + OK, + FAIL, + NEED_MORE_INPUT, + WHITESPACE, + WORD, + THING +}; +const char * STATUSES[] = { + "OK", + "FAIL", + "NEED_MORE_INPUT", + "WHITESPACE", + "WORD", + "THING" +}; + +#define YYGETSTATE() in.state +#define YYSETSTATE(s) in.state = s +#define YYFILL() do { \ + printf("< Returning for more input\n"); \ + return NEED_MORE_INPUT; \ +} while (0) + +static status_t lex(input_t &in) +{ +switch (YYGETSTATE()) { +default: goto yy0; +case 0: goto yyFillLabel0; +case 1: goto yyFillLabel1; +case 2: goto yyFillLabel2; +case 3: goto yyFillLabel3; +case 4: goto yyFillLabel4; +case 5: goto yyFillLabel5; +case 6: goto yyFillLabel6; +case 7: goto yyFillLabel7; +case 8: goto yyFillLabel8; +case 9: goto yyFillLabel9; +case 10: goto yyFillLabel10; +case 11: goto yyFillLabel11; +case 12: goto yyFillLabel12; +case 13: goto yyFillLabel13; +case 14: goto yyFillLabel14; +case 15: goto yyFillLabel15; +case 16: goto yyFillLabel16; +case 17: goto yyFillLabel17; +case 18: goto yyFillLabel18; +case 19: goto yyFillLabel19; +case 20: goto yyFillLabel20; +} + + + +yy1: +yy0: +yy1_: +yyFillLabel0: + in.yych = *in.cur; + switch (in.yych) { + case 0x00: + if (in.lim <= in.cur) { + YYSETSTATE(0); + YYFILL (); + } + goto yy2; + case '\n': + case ' ': goto yy6; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': goto yy9; + case 'T': goto yy12; + default: goto yy4; + } +yy2: + ++in.cur; + { printf("< EOF\n"); return OK; } +yy4: + ++in.cur; + { printf("< Unexpected character >%c<\n", in.yych); return FAIL; } +yy6: + ++in.cur; +yy6_: +yyFillLabel1: + in.yych = *in.cur; +yy7: + switch (in.yych) { + case '\n': + case ' ': goto yy6; + default: + if (in.lim <= in.cur) { + YYSETSTATE(1); + YYFILL (); + } + goto yy8; + } +yy8: + { printf("< whitespace\n"); return WHITESPACE; } +yy9: + ++in.cur; +yy9_: +yyFillLabel2: + in.yych = *in.cur; +yy10: + switch (in.yych) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': goto yy9; + default: + if (in.lim <= in.cur) { + YYSETSTATE(2); + YYFILL (); + } + goto yy11; + } +yy11: + { printf("< word\n"); return WORD; } +yy12: + ++in.cur; +yy12_: +yyFillLabel3: + in.yych = *in.cur; + switch (in.yych) { + case 0x00: + if (in.lim <= in.cur) { + YYSETSTATE(3); + YYFILL (); + } + goto yy11; + case 'H': goto yy13; + default: goto yy10; + } +yy13: + ++in.cur; +yy13_: +yyFillLabel4: + in.yych = *in.cur; + switch (in.yych) { + case 0x00: + if (in.lim <= in.cur) { + YYSETSTATE(4); + YYFILL (); + } + goto yy11; + case 'I': goto yy14; + default: goto yy10; + } +yy14: + ++in.cur; +yy14_: +yyFillLabel5: + in.yych = *in.cur; + switch (in.yych) { + case 0x00: + if (in.lim <= in.cur) { + YYSETSTATE(5); + YYFILL (); + } + goto yy11; + case 'N': goto yy15; + default: goto yy10; + } +yy15: + ++in.cur; +yy15_: +yyFillLabel6: + in.yych = *in.cur; + switch (in.yych) { + case 0x00: + if (in.lim <= in.cur) { + YYSETSTATE(6); + YYFILL (); + } + goto yy11; + case 'G': goto yy16; + default: goto yy10; + } +yy16: + in.mark = ++in.cur; +yy16_: +yyFillLabel7: + in.yych = *in.cur; + switch (in.yych) { + case 0x00: + if (in.lim <= in.cur) { + YYSETSTATE(7); + YYFILL (); + } + goto yy11; + case '\n': goto yy17; + default: goto yy10; + } +yy17: + ++in.cur; +yy17_: +yyFillLabel8: + in.yych = *in.cur; + switch (in.yych) { + case 'W': goto yy19; + default: + if (in.lim <= in.cur) { + YYSETSTATE(8); + YYFILL (); + } + goto yy18; + } +yy18: + in.cur = in.mark; + goto yy11; +yy19: + ++in.cur; +yy19_: +yyFillLabel9: + in.yych = *in.cur; + switch (in.yych) { + case 'I': goto yy20; + default: + if (in.lim <= in.cur) { + YYSETSTATE(9); + YYFILL (); + } + goto yy18; + } +yy20: + ++in.cur; +yy20_: +yyFillLabel10: + in.yych = *in.cur; + switch (in.yych) { + case 'T': goto yy21; + default: + if (in.lim <= in.cur) { + YYSETSTATE(10); + YYFILL (); + } + goto yy18; + } +yy21: + ++in.cur; +yy21_: +yyFillLabel11: + in.yych = *in.cur; + switch (in.yych) { + case 'H': goto yy22; + default: + if (in.lim <= in.cur) { + YYSETSTATE(11); + YYFILL (); + } + goto yy18; + } +yy22: + ++in.cur; +yy22_: +yyFillLabel12: + in.yych = *in.cur; + switch (in.yych) { + case '\n': goto yy23; + default: + if (in.lim <= in.cur) { + YYSETSTATE(12); + YYFILL (); + } + goto yy18; + } +yy23: + ++in.cur; +yy23_: +yyFillLabel13: + in.yych = *in.cur; + switch (in.yych) { + case 'N': goto yy24; + default: + if (in.lim <= in.cur) { + YYSETSTATE(13); + YYFILL (); + } + goto yy18; + } +yy24: + ++in.cur; +yy24_: +yyFillLabel14: + in.yych = *in.cur; + switch (in.yych) { + case 'E': goto yy25; + default: + if (in.lim <= in.cur) { + YYSETSTATE(14); + YYFILL (); + } + goto yy18; + } +yy25: + ++in.cur; +yy25_: +yyFillLabel15: + in.yych = *in.cur; + switch (in.yych) { + case 'W': goto yy26; + default: + if (in.lim <= in.cur) { + YYSETSTATE(15); + YYFILL (); + } + goto yy18; + } +yy26: + ++in.cur; +yy26_: +yyFillLabel16: + in.yych = *in.cur; + switch (in.yych) { + case 'L': goto yy27; + default: + if (in.lim <= in.cur) { + YYSETSTATE(16); + YYFILL (); + } + goto yy18; + } +yy27: + ++in.cur; +yy27_: +yyFillLabel17: + in.yych = *in.cur; + switch (in.yych) { + case 'I': goto yy28; + default: + if (in.lim <= in.cur) { + YYSETSTATE(17); + YYFILL (); + } + goto yy18; + } +yy28: + ++in.cur; +yy28_: +yyFillLabel18: + in.yych = *in.cur; + switch (in.yych) { + case 'N': goto yy29; + default: + if (in.lim <= in.cur) { + YYSETSTATE(18); + YYFILL (); + } + goto yy18; + } +yy29: + ++in.cur; +yy29_: +yyFillLabel19: + in.yych = *in.cur; + switch (in.yych) { + case 'E': goto yy30; + default: + if (in.lim <= in.cur) { + YYSETSTATE(19); + YYFILL (); + } + goto yy18; + } +yy30: + ++in.cur; +yy30_: +yyFillLabel20: + in.yych = *in.cur; + switch (in.yych) { + case 'S': goto yy31; + default: + if (in.lim <= in.cur) { + YYSETSTATE(20); + YYFILL (); + } + goto yy18; + } +yy31: + ++in.cur; + { printf("< Thing w/ newlines\n"); return THING; } + +} + +int main() +{ + int fds[2]; + pipe(fds); + fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK); + FILE * write = fdopen(fds[1], "w"); + FILE * read = fdopen(fds[0], "r"); + input_t in(read); + + const char * packets[] = { + "THING\n", + "WITH\n", + "NEWLINES\n", + "H", "E", "L", "O", "\n", + "HELO\n", + "THING\nWITH\n", + "NEWLINES" + }; + size_t num_packets = sizeof(packets) / sizeof(char *); + size_t current_packet = 0; + + enum status_t result = NEED_MORE_INPUT; + + while (OK != result) { + switch (result) { + case NEED_MORE_INPUT: + if (current_packet == num_packets) { + printf("Not enough input\n"); + goto end; + } + + fwrite(packets[current_packet], strlen(packets[current_packet]), 1, write); + fflush(write); + current_packet++; + printf("Packet %lu / %lu written\n", current_packet, num_packets); + + if (current_packet == num_packets) { + printf("%lu / %lu packets sent, Closing down communication channel\n", + current_packet, num_packets); + fclose(write); + write = NULL; + } + + in.fill(); + break; + + case FAIL: + goto end; + + default: + // careful, need to reset state (re2c forgets to do it) + YYSETSTATE(0); + break; + } + + result = lex(in); + printf("Received response from lexer: %s\n", STATUSES[result]); + } + +end: + + // cleanup + fclose(read); + if (write) { + fclose(write); + } + + return result == OK ? 0 : 1; +} + +#undef YYGETSTATE +#undef YYSETSTATE +#undef YYFILL diff --git a/re2c/test/eof/nonblocking_push.fi.re b/re2c/test/eof/nonblocking_push.fi.re new file mode 100644 index 00000000..1537aa6f --- /dev/null +++ b/re2c/test/eof/nonblocking_push.fi.re @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include + +/*!max:re2c*/ +static const size_t SIZE = 4096; + +struct input_t { + char buf[SIZE + YYMAXFILL]; + char *lim; + char *cur; + char *tok; + char *mark; + int state; + unsigned yyaccept; + char yych; + FILE *file; + + input_t(FILE * file) + : buf() + , lim(buf + SIZE) + , cur(lim) + , tok(lim) + , mark(lim) + , state(0) + , yyaccept(0) + , yych(0) + , file(file) + {} + + bool fill() + { + const size_t free = (tok - buf) + SIZE - (lim - buf); + if (free < 1) return false; + const size_t prefix = (tok - buf); + + memmove(buf, tok, buf - tok + SIZE); + lim -= prefix; + cur -= prefix; + tok -= prefix; + mark -= prefix; + size_t to_read = SIZE - (lim - buf); + printf("> Reading input, can take up to %lu bytes\n", to_read); + size_t bytes_read = fread(lim, 1, to_read, file); + lim += bytes_read; + lim[0] = 0; + + // simulate the END packet (can as well send a normal packet) + if (feof(file)) ++lim; + + // quick make a copy of buffer with newlines replaced w/ _ + char b[40]; + snprintf(b, 40, "%s", buf); + for(int i = 0; i < 40; i++) { + if ('\n' == b[i]) { b[i] = '_'; } + } + printf("> Read %lu bytes from input, current buffer: >%.40s<\n", bytes_read, b); + + return true; + } +}; + +enum status_t { + OK, + FAIL, + NEED_MORE_INPUT, + WHITESPACE, + WORD, + THING +}; +const char * STATUSES[] = { + "OK", + "FAIL", + "NEED_MORE_INPUT", + "WHITESPACE", + "WORD", + "THING" +}; + +#define YYGETSTATE() in.state +#define YYSETSTATE(s) in.state = s +#define YYFILL() do { \ + printf("< Returning for more input\n"); \ + return NEED_MORE_INPUT; \ +} while (0) + +static status_t lex(input_t &in) +{ +/*!getstate:re2c*/ +/*!re2c + re2c:define:YYCTYPE = char; + re2c:define:YYCURSOR = in.cur; + re2c:define:YYLIMIT = in.lim; + re2c:define:YYMARKER = in.mark; + re2c:variable:yych = in.yych; + re2c:eof = 0; + + * { printf("< Unexpected character >%c<\n", in.yych); return FAIL; } + [\x00] { printf("< EOF\n"); return OK; } + [\n ]+ { printf("< whitespace\n"); return WHITESPACE; } + [a-zA-Z]+ { printf("< word\n"); return WORD; } + "THING\nWITH\nNEWLINES" { printf("< Thing w/ newlines\n"); return THING; } +*/ +} + +int main() +{ + int fds[2]; + pipe(fds); + fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK); + FILE * write = fdopen(fds[1], "w"); + FILE * read = fdopen(fds[0], "r"); + input_t in(read); + + const char * packets[] = { + "THING\n", + "WITH\n", + "NEWLINES\n", + "H", "E", "L", "O", "\n", + "HELO\n", + "THING\nWITH\n", + "NEWLINES" + }; + size_t num_packets = sizeof(packets) / sizeof(char *); + size_t current_packet = 0; + + enum status_t result = NEED_MORE_INPUT; + + while (OK != result) { + switch (result) { + case NEED_MORE_INPUT: + if (current_packet == num_packets) { + printf("Not enough input\n"); + goto end; + } + + fwrite(packets[current_packet], strlen(packets[current_packet]), 1, write); + fflush(write); + current_packet++; + printf("Packet %lu / %lu written\n", current_packet, num_packets); + + if (current_packet == num_packets) { + printf("%lu / %lu packets sent, Closing down communication channel\n", + current_packet, num_packets); + fclose(write); + write = NULL; + } + + in.fill(); + break; + + case FAIL: + goto end; + + default: + // careful, need to reset state (re2c forgets to do it) + YYSETSTATE(0); + break; + } + + result = lex(in); + printf("Received response from lexer: %s\n", STATUSES[result]); + } + +end: + + // cleanup + fclose(read); + if (write) { + fclose(write); + } + + return result == OK ? 0 : 1; +} + +#undef YYGETSTATE +#undef YYSETSTATE +#undef YYFILL -- 2.40.0