diff --git a/Makefile b/Makefile index 499239fd9..3613bc941 100644 --- a/Makefile +++ b/Makefile @@ -117,6 +117,7 @@ SUBDIR += tests/subtract SUBDIR += tests/determinise SUBDIR += tests/endids SUBDIR += tests/epsilons +SUBDIR += tests/fsm SUBDIR += tests/glob SUBDIR += tests/like SUBDIR += tests/literal diff --git a/include/fsm/fsm.h b/include/fsm/fsm.h index 2fea117cd..269ee5c87 100644 --- a/include/fsm/fsm.h +++ b/include/fsm/fsm.h @@ -37,12 +37,6 @@ typedef unsigned int fsm_end_id_t; #define FSM_END_ID_MAX UINT_MAX -/* struct used to return a collection of end IDs. */ -struct fsm_end_ids { - unsigned count; - fsm_end_id_t ids[1]; -}; - /* * Create a new FSM. This is to be freed with fsm_free(). A structure allocated * from fsm_new() is expected to be passed as the "fsm" argument to the @@ -222,29 +216,31 @@ fsm_setendid(struct fsm *fsm, fsm_end_id_t id); * Returns 1 on success, 0 on error. * */ int -fsm_setendidstate(struct fsm *fsm, fsm_state_t end_state, fsm_end_id_t id); +fsm_endid_set(struct fsm *fsm, fsm_state_t end_state, fsm_end_id_t id); /* Get the end IDs associated with an end state, if any. - * If id_buf has enough cells to store all the end IDs (according - * to id_buf_count) then they are written into id_buf[] and - * *ids_written is set to the number of IDs. The end IDs in the - * buffer may appear in any order, but should not have duplicates. + * id_buf is expected to have enough cells (according to id_buf_count) + * to store all the end IDs. You can find this with fsm_endid_count(). + * + * The end IDs in the buffer may appear in any order, + * but will not have duplicates. + * + * A state with no end IDs set is considered equivalent to a state + * that has the empty set, this API does not distinguish these cases. + * This is not an error. + * + * It is an error to attempt to get end IDs associated with a state + * that is not marked as an end state. * * Returns 0 if there is not enough space in id_buf for the * end IDs, or 1 if zero or more end IDs were returned. */ -enum fsm_getendids_res { - FSM_GETENDIDS_NOT_FOUND, - FSM_GETENDIDS_FOUND, - FSM_GETENDIDS_ERROR_INSUFFICIENT_SPACE = -1 -}; -enum fsm_getendids_res -fsm_getendids(const struct fsm *fsm, fsm_state_t end_state, - size_t id_buf_count, fsm_end_id_t *id_buf, - size_t *ids_written); +int +fsm_endid_get(const struct fsm *fsm, fsm_state_t end_state, + size_t id_buf_count, fsm_end_id_t *id_buf); /* Get the number of end IDs associated with an end state. */ size_t -fsm_getendidcount(const struct fsm *fsm, fsm_state_t end_state); +fsm_endid_count(const struct fsm *fsm, fsm_state_t end_state); /* Callback function to remap the end ids of a state. This function can * remap to fewer end ids, but cannot add additional end ids, and cannot diff --git a/include/fsm/options.h b/include/fsm/options.h index b4193cc78..e66c16b71 100644 --- a/include/fsm/options.h +++ b/include/fsm/options.h @@ -65,12 +65,15 @@ struct fsm_options { const char *cp; /* TODO: explain. for C code fragment output */ - int (*leaf)(FILE *, const struct fsm_end_ids *ids, + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque); void *leaf_opaque; /* TODO: explain. for C code fragment output */ - int (*endleaf)(FILE *, const struct fsm_end_ids *ids, + /* Placement in the output stream depends on the format. + * This replaces an entire "return xyz;" statement for C-like formats, + * but appends extra information for others. */ + int (*endleaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *endleaf_opaque); void *endleaf_opaque; diff --git a/src/fsm/main.c b/src/fsm/main.c index d6cd1e83c..a255ae8ee 100644 --- a/src/fsm/main.c +++ b/src/fsm/main.c @@ -477,17 +477,14 @@ main(int argc, char *argv[]) struct fsm *q; if ((op & OP_ARITY) == 1) { - if (argc > 1) { - usage(); - exit(EXIT_FAILURE); - } + /* argc < 1 is okay */ q = fsm_parse((argc == 0) ? stdin : xopen(argv[0]), &opt); if (q == NULL) { exit(EXIT_FAILURE); } } else { - if (argc != 2) { + if (argc < 2) { usage(); exit(EXIT_FAILURE); } @@ -610,6 +607,17 @@ main(int argc, char *argv[]) printf("=> total %g ms (avg %g ms)\n", elapsed, elapsed / iterations); } + /* we're done consuming filenames, remaining argv is text to match */ + if ((op & OP_ARITY) == 1) { + if (argc > 0) { + argc -= 1; + argv += 1; + } + } else { + argc -= 2; + argv += 2; + } + /* henceforth, r is $?-convention (0 for success) */ if (fsm == NULL) { @@ -661,14 +669,15 @@ main(int argc, char *argv[]) } } - /* TODO: optional -- to delimit texts as opposed to .fsm filenames */ - if (op == OP_IDENTITY && argc > 0) { + /* match text */ + if (argc > 0) { int i; /* TODO: option to print input texts which match. like grep(1) does. * This is not the same as printing patterns which match (by associating * a pattern to the end state), like lx(1) does */ + /* TODO: optional -- to delimit texts as opposed to .fsm filenames */ for (i = 0; i < argc; i++) { fsm_state_t state; int e; @@ -694,7 +703,7 @@ main(int argc, char *argv[]) continue; } - /* TODO: option to print state number? */ + /* TODO: option to print matching end-ids */ } } diff --git a/src/libfsm/clone.c b/src/libfsm/clone.c index 78511b12c..69aedaa63 100644 --- a/src/libfsm/clone.c +++ b/src/libfsm/clone.c @@ -127,15 +127,13 @@ static int copy_end_ids_cb(fsm_state_t state, const fsm_end_id_t id, void *opaque) { struct copy_end_ids_env *env = opaque; - enum fsm_endid_set_res sres; assert(env->tag == 'c'); #if LOG_CLONE_ENDIDS fprintf(stderr, "clone[%d] <- %d\n", state, id); #endif - sres = fsm_endid_set(env->dst, state, id); - if (sres == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { + if (!fsm_endid_set(env->dst, state, id)) { env->ok = 0; return 0; } diff --git a/src/libfsm/consolidate.c b/src/libfsm/consolidate.c index 4518d3926..a000a4c7b 100644 --- a/src/libfsm/consolidate.c +++ b/src/libfsm/consolidate.c @@ -231,19 +231,14 @@ static int consolidate_end_ids_cb(fsm_state_t state, const fsm_end_id_t *ids, size_t num_ids, void *opaque) { struct consolidate_end_ids_env *env = opaque; - enum fsm_endid_set_res sres; fsm_state_t s; assert(env->tag == 'C'); assert(state < env->mapping_count); s = env->mapping[state]; - sres = fsm_endid_set_bulk(env->dst, s, num_ids, ids, FSM_ENDID_BULK_APPEND); - if (sres == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { - return 0; - } - - return 1; + return fsm_endid_set_bulk(env->dst, s, + num_ids, ids, FSM_ENDID_BULK_APPEND); } static int diff --git a/src/libfsm/endids.c b/src/libfsm/endids.c index 1fc98ae68..66860e88a 100644 --- a/src/libfsm/endids.c +++ b/src/libfsm/endids.c @@ -69,13 +69,11 @@ fsm_setendid(struct fsm *fsm, fsm_end_id_t id) /* for every end state */ for (i = 0; i < fsm->statecount; i++) { if (fsm_isend(fsm, i)) { - enum fsm_endid_set_res sres; #if LOG_ENDIDS > 3 fprintf(stderr, "fsm_setendid: setting id %u on state %d\n", id, i); #endif - sres = fsm_endid_set(fsm, i, id); - if (sres == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { + if (!fsm_endid_set(fsm, i, id)) { return 0; } } @@ -84,31 +82,6 @@ fsm_setendid(struct fsm *fsm, fsm_end_id_t id) return 1; } -int -fsm_setendidstate(struct fsm *fsm, fsm_state_t end_state, fsm_end_id_t id) -{ - enum fsm_endid_set_res sres = fsm_endid_set(fsm, end_state, id); - if (sres == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { - return 0; - } - return 1; -} - -enum fsm_getendids_res -fsm_getendids(const struct fsm *fsm, fsm_state_t end_state, - size_t id_buf_count, fsm_end_id_t *id_buf, - size_t *ids_written) -{ - return fsm_endid_get(fsm, end_state, - id_buf_count, id_buf, ids_written); -} - -size_t -fsm_getendidcount(const struct fsm *fsm, fsm_state_t end_state) -{ - return fsm_endid_count(fsm, end_state); -} - int fsm_endid_init(struct fsm *fsm) { @@ -394,7 +367,7 @@ allocate_ids(const struct fsm *fsm, struct end_info_ids *prev, size_t n) return f_realloc(fsm->opt->alloc, prev, id_alloc_size); } -enum fsm_endid_set_res +int fsm_endid_set(struct fsm *fsm, fsm_state_t state, fsm_end_id_t id) { @@ -406,7 +379,7 @@ fsm_endid_set(struct fsm *fsm, struct endid_info_bucket *b = endid_find_bucket(fsm, state); if (b == NULL) { - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } LOG_2("fsm_endid_set: state %d, bucket %p\n", state, (void *)b); @@ -416,7 +389,7 @@ fsm_endid_set(struct fsm *fsm, ids = allocate_ids(fsm, NULL, DEF_BUCKET_ID_COUNT); if (ids == NULL) { - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } ids->ids[0] = id; @@ -427,7 +400,7 @@ fsm_endid_set(struct fsm *fsm, b->ids = ids; ei->buckets_used++; - return FSM_ENDID_SET_ADDED; + return 1; } else if (b->state == state) { size_t ind; @@ -444,7 +417,7 @@ fsm_endid_set(struct fsm *fsm, nids = allocate_ids(fsm, b->ids, nceil); if (nids == NULL) { - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; /* alloc fail */ + return 0; /* alloc fail */ } nids->ceil = nceil; b->ids = nids; @@ -465,7 +438,7 @@ fsm_endid_set(struct fsm *fsm, } else if (b->ids->ids[ind] == id) { /* already present, our work is done! */ LOG_2("fsm_endid_set: already present, skipping\n"); - return FSM_ENDID_SET_ALREADY_PRESENT; + return 1; } else { /* need to shift items up to make room for id */ memmove(&b->ids->ids[ind+1], &b->ids->ids[ind], @@ -481,10 +454,10 @@ fsm_endid_set(struct fsm *fsm, (void)dump_buckets; DBG_3(dump_buckets("set_dump", ei)); - return FSM_ENDID_SET_ADDED; + return 1; } else { assert(!"unreachable: endid_find_bucket failed"); - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } } @@ -505,7 +478,7 @@ cmp_endids(const void *pa, const void *pb) return 0; } -enum fsm_endid_set_res +int fsm_endid_set_bulk(struct fsm *fsm, fsm_state_t state, size_t num_ids, const fsm_end_id_t *ids, enum fsm_endid_bulk_op op) { @@ -519,7 +492,7 @@ fsm_endid_set_bulk(struct fsm *fsm, b = endid_find_bucket(fsm, state); if (b == NULL) { - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } if (b->state == state) { @@ -542,12 +515,12 @@ fsm_endid_set_bulk(struct fsm *fsm, if (new_ceil < total_count) { /* num_ids is too large? */ - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } new_ids = allocate_ids(fsm, b->ids, new_ceil); if (new_ids == NULL) { - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } b->ids = new_ids; @@ -577,12 +550,12 @@ fsm_endid_set_bulk(struct fsm *fsm, if (n < num_ids) { /* num_ids is too large? */ - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } new_ids = allocate_ids(fsm, NULL, n); if (new_ids == NULL) { - return FSM_ENDID_SET_ERROR_ALLOC_FAIL; + return 0; } memcpy(&new_ids->ids[0], &ids[0], num_ids * sizeof ids[0]); @@ -619,7 +592,7 @@ fsm_endid_set_bulk(struct fsm *fsm, b->ids->count = j; } - return FSM_ENDID_SET_ADDED; + return 1; } int @@ -708,26 +681,21 @@ fsm_endid_count(const struct fsm *fsm, return 0; } -enum fsm_getendids_res +int fsm_endid_get(const struct fsm *fsm, fsm_state_t end_state, - size_t id_buf_count, fsm_end_id_t *id_buf, - size_t *ids_written) + size_t count, fsm_end_id_t *ids) { size_t i; - size_t written = 0; const struct endid_info *ei = NULL; uint64_t hash = hash_id(end_state); uint64_t mask; - (void)written; - assert(fsm != NULL); ei = fsm->endid_info; assert(ei != NULL); - assert(id_buf != NULL); - assert(ids_written != NULL); + assert(ids != NULL); mask = ei->bucket_count - 1; /* bucket count is a power of 2 */ @@ -748,26 +716,26 @@ fsm_endid_get(const struct fsm *fsm, fsm_state_t end_state, #if LOG_ENDIDS > 2 fprintf(stderr, "fsm_endid_get: not found\n"); #endif - *ids_written = 0; /* not found */ - return FSM_GETENDIDS_NOT_FOUND; - } else if (b->state == end_state) { + return 1; /* not an error */ + } + + if (b->state == end_state) { size_t id_i; - if (b->ids->count > id_buf_count) { + if (b->ids->count > count) { #if LOG_ENDIDS > 2 fprintf(stderr, "fsm_endid_get: insufficient space\n"); #endif - return FSM_GETENDIDS_ERROR_INSUFFICIENT_SPACE; + return 0; /* insufficient space */ } for (id_i = 0; id_i < b->ids->count; id_i++) { #if LOG_ENDIDS > 2 fprintf(stderr, "fsm_endid_get: writing id[%zu]: %d\n", id_i, b->ids->ids[id_i]); #endif - id_buf[id_i] = b->ids->ids[id_i]; + ids[id_i] = b->ids->ids[id_i]; } /* todo: could sort them here, if it matters. */ - *ids_written = b->ids->count; - return FSM_GETENDIDS_FOUND; + return 1; } else { /* collision */ #if LOG_ENDIDS > 4 fprintf(stderr, "fsm_endid_get: collision\n"); @@ -777,7 +745,7 @@ fsm_endid_get(const struct fsm *fsm, fsm_state_t end_state, } assert(!"unreachable"); - return FSM_GETENDIDS_NOT_FOUND; + return 0; } struct carry_env { @@ -790,14 +758,12 @@ struct carry_env { static int carry_iter_cb(fsm_state_t state, fsm_end_id_t id, void *opaque) { - enum fsm_endid_set_res sres; struct carry_env *env = opaque; assert(env->tag == 'C'); (void)state; - sres = fsm_endid_set(env->dst, env->dst_state, id); - if (sres == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { + if (!fsm_endid_set(env->dst, env->dst_state, id)) { env->ok = 0; return 0; } diff --git a/src/libfsm/endids.h b/src/libfsm/endids.h index 6c46567b3..a5697f10b 100644 --- a/src/libfsm/endids.h +++ b/src/libfsm/endids.h @@ -10,15 +10,6 @@ fsm_endid_init(struct fsm *fsm); void fsm_endid_free(struct fsm *fsm); -enum fsm_endid_set_res { - FSM_ENDID_SET_ADDED, - FSM_ENDID_SET_ALREADY_PRESENT, - FSM_ENDID_SET_ERROR_ALLOC_FAIL = -1 -}; -enum fsm_endid_set_res -fsm_endid_set(struct fsm *fsm, - fsm_state_t state, fsm_end_id_t id); - /* Sets end ids in a bulk operation. * * Repeatedly calling fsm_endid_set will end up with quadratic behavior. This @@ -34,26 +25,16 @@ fsm_endid_set(struct fsm *fsm, * * The caller maintains ownership of ids, and must free it if needed. * - * Only FSM_ENDID_SET_ADDED and FSM_ENDID_SET_ERROR_ALLOC_FAIL - * are returned. + * Returns 1 on success, 0 on failure. */ enum fsm_endid_bulk_op { FSM_ENDID_BULK_REPLACE = 0, FSM_ENDID_BULK_APPEND = 1, }; -enum fsm_endid_set_res +int fsm_endid_set_bulk(struct fsm *fsm, fsm_state_t state, size_t num_ids, const fsm_end_id_t *ids, enum fsm_endid_bulk_op op); -size_t -fsm_endid_count(const struct fsm *fsm, - fsm_state_t state); - -enum fsm_getendids_res -fsm_endid_get(const struct fsm *fsm, fsm_state_t end_state, - size_t id_buf_count, fsm_end_id_t *id_buf, - size_t *ids_written); - int fsm_endid_carry(const struct fsm *src_fsm, const struct state_set *src_set, struct fsm *dst_fsm, fsm_state_t dst_state); diff --git a/src/libfsm/epsilons.c b/src/libfsm/epsilons.c index e87d9d974..f8bb1d9d3 100644 --- a/src/libfsm/epsilons.c +++ b/src/libfsm/epsilons.c @@ -405,9 +405,7 @@ carry_endids(struct fsm *fsm, struct state_set *states, /* add them */ for (i = 0; i < env.count; i++) { - enum fsm_endid_set_res sres; - sres = fsm_endid_set(fsm, dst_state, env.ids[i]); - if (sres == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { + if (!fsm_endid_set(fsm, dst_state, env.ids[i])) { env.ok = 0; goto cleanup; } diff --git a/src/libfsm/lexer.c b/src/libfsm/lexer.c index 7213bb142..8bd374cec 100644 --- a/src/libfsm/lexer.c +++ b/src/libfsm/lexer.c @@ -12,6 +12,8 @@ static enum lx_token z0(struct lx *lx); static enum lx_token z1(struct lx *lx); static enum lx_token z2(struct lx *lx); static enum lx_token z3(struct lx *lx); +static enum lx_token z4(struct lx *lx); +static enum lx_token z5(struct lx *lx); #if __STDC_VERSION__ >= 199901L inline @@ -180,25 +182,35 @@ z0(struct lx *lx) switch (state) { case S0: /* start */ switch ((unsigned char) c) { - case '\'': state = S2; break; + case '\n': state = S2; break; default: state = S1; break; } break; case S1: /* e.g. "a" */ - lx_ungetc(lx, c); return TOK_CHAR; + lx_ungetc(lx, c); return lx->z(lx); - case S2: /* e.g. "'" */ - lx_ungetc(lx, c); return lx->z = z3, TOK_LABEL; + case S2: /* e.g. "" */ + lx_ungetc(lx, c); return lx->z = z1, lx->z(lx); default: ; /* unreached */ } - if (lx->push != NULL) { - if (-1 == lx->push(lx->buf_opaque, c)) { - return TOK_ERROR; + switch (state) { + case S0: + case S1: + case S2: + break; + + default: + if (lx->push != NULL) { + if (-1 == lx->push(lx->buf_opaque, (char)c)) { + return TOK_ERROR; + } } + break; + } } @@ -206,8 +218,8 @@ z0(struct lx *lx) switch (state) { case NONE: return TOK_EOF; - case S1: return TOK_CHAR; - case S2: return TOK_LABEL; + case S1: return TOK_EOF; + case S2: return TOK_EOF; default: errno = EINVAL; return TOK_ERROR; } } @@ -218,7 +230,7 @@ z1(struct lx *lx) int c; enum { - S0, S1, S2, S3, S4, S5, S6, S7, NONE + S0, S1, S2, S3, S4, S5, NONE } state; assert(lx != NULL); @@ -239,27 +251,29 @@ z1(struct lx *lx) switch (state) { case S0: /* start */ switch ((unsigned char) c) { - case '"': state = S2; break; - case '\\': state = S3; break; - default: state = S1; break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = S1; break; + case ',': state = S2; break; + case '#': state = S3; break; + case '\t': + case '\n': + case '\r': + case ' ': state = S4; break; + case ']': state = S5; break; + default: lx->lgetc = NULL; return TOK_UNKNOWN; } break; - case S1: /* e.g. "a" */ - lx_ungetc(lx, c); return TOK_CHAR; - - case S2: /* e.g. "\"" */ - lx_ungetc(lx, c); return lx->z = z3, TOK_LABEL; - - case S3: /* e.g. "\\" */ + case S1: /* e.g. "0" */ switch ((unsigned char) c) { - case '"': - case '\\': - case 'f': - case 'n': - case 'r': - case 't': - case 'v': state = S4; break; case '0': case '1': case '2': @@ -267,17 +281,160 @@ z1(struct lx *lx) case '4': case '5': case '6': - case '7': state = S5; break; - case 'x': state = S6; break; - default: lx_ungetc(lx, c); return TOK_CHAR; + case '7': + case '8': + case '9': break; + default: lx_ungetc(lx, c); return TOK_ENDID; } break; - case S4: /* e.g. "\\f" */ - lx_ungetc(lx, c); return TOK_ESC; + case S2: /* e.g. "," */ + lx_ungetc(lx, c); return TOK_COMMA; - case S5: /* e.g. "\\0" */ + case S3: /* e.g. "#" */ + lx_ungetc(lx, c); return lx->z = z0, lx->z(lx); + + case S4: /* e.g. "\\x09" */ + switch ((unsigned char) c) { + case '\t': + case '\n': + case '\r': + case ' ': break; + default: lx_ungetc(lx, c); return lx->z(lx); + } + break; + + case S5: /* e.g. "]" */ + lx_ungetc(lx, c); return lx->z = z5, TOK_CLOSEENDIDS; + + default: + ; /* unreached */ + } + + switch (state) { + case S3: + case S4: + break; + + default: + if (lx->push != NULL) { + if (-1 == lx->push(lx->buf_opaque, (char)c)) { + return TOK_ERROR; + } + } + break; + + } + } + + lx->lgetc = NULL; + + switch (state) { + case NONE: return TOK_EOF; + case S1: return TOK_ENDID; + case S2: return TOK_COMMA; + case S3: return TOK_EOF; + case S4: return TOK_EOF; + case S5: return TOK_CLOSEENDIDS; + default: errno = EINVAL; return TOK_ERROR; + } +} + +static enum lx_token +z2(struct lx *lx) +{ + int c; + + enum { + S0, S1, S2, NONE + } state; + + assert(lx != NULL); + + if (lx->clear != NULL) { + lx->clear(lx->buf_opaque); + } + + state = NONE; + + lx->start = lx->end; + + while (c = lx_getc(lx), c != EOF) { + if (state == NONE) { + state = S0; + } + + switch (state) { + case S0: /* start */ switch ((unsigned char) c) { + case '\'': state = S2; break; + default: state = S1; break; + } + break; + + case S1: /* e.g. "a" */ + lx_ungetc(lx, c); return TOK_CHAR; + + case S2: /* e.g. "'" */ + lx_ungetc(lx, c); return lx->z = z5, TOK_LABEL; + + default: + ; /* unreached */ + } + + if (lx->push != NULL) { + if (-1 == lx->push(lx->buf_opaque, (char)c)) { + return TOK_ERROR; + } + } + } + + lx->lgetc = NULL; + + switch (state) { + case NONE: return TOK_EOF; + case S1: return TOK_CHAR; + case S2: return TOK_LABEL; + default: errno = EINVAL; return TOK_ERROR; + } +} + +static enum lx_token +z3(struct lx *lx) +{ + int c; + + enum { + S0, S1, S2, S3, S4, S5, S6, S7, NONE + } state; + + assert(lx != NULL); + + if (lx->clear != NULL) { + lx->clear(lx->buf_opaque); + } + + state = NONE; + + lx->start = lx->end; + + while (c = lx_getc(lx), c != EOF) { + if (state == NONE) { + state = S0; + } + + switch (state) { + case S0: /* start */ + switch ((unsigned char) c) { + case '\\': state = S1; break; + case '"': state = S3; break; + default: state = S2; break; + } + break; + + case S1: /* e.g. "\\" */ + switch ((unsigned char) c) { + case 'x': state = S4; break; case '0': case '1': case '2': @@ -285,12 +442,25 @@ z1(struct lx *lx) case '4': case '5': case '6': - case '7': break; - default: lx_ungetc(lx, c); return TOK_OCT; + case '7': state = S5; break; + case '"': + case '\\': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': state = S6; break; + default: lx_ungetc(lx, c); return TOK_CHAR; } break; - case S6: /* e.g. "\\x" */ + case S2: /* e.g. "a" */ + lx_ungetc(lx, c); return TOK_CHAR; + + case S3: /* e.g. "\"" */ + lx_ungetc(lx, c); return lx->z = z5, TOK_LABEL; + + case S4: /* e.g. "\\x" */ switch ((unsigned char) c) { case '0': case '1': @@ -318,6 +488,23 @@ z1(struct lx *lx) } break; + case S5: /* e.g. "\\0" */ + switch ((unsigned char) c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': break; + default: lx_ungetc(lx, c); return TOK_OCT; + } + break; + + case S6: /* e.g. "\\f" */ + lx_ungetc(lx, c); return TOK_ESC; + case S7: /* e.g. "\\xa" */ switch ((unsigned char) c) { case '0': @@ -351,7 +538,7 @@ z1(struct lx *lx) } if (lx->push != NULL) { - if (-1 == lx->push(lx->buf_opaque, c)) { + if (-1 == lx->push(lx->buf_opaque, (char)c)) { return TOK_ERROR; } } @@ -362,17 +549,17 @@ z1(struct lx *lx) switch (state) { case NONE: return TOK_EOF; case S1: return TOK_CHAR; - case S2: return TOK_LABEL; - case S3: return TOK_CHAR; - case S4: return TOK_ESC; + case S2: return TOK_CHAR; + case S3: return TOK_LABEL; case S5: return TOK_OCT; + case S6: return TOK_ESC; case S7: return TOK_HEX; default: errno = EINVAL; return TOK_ERROR; } } static enum lx_token -z2(struct lx *lx) +z4(struct lx *lx) { int c; @@ -407,7 +594,7 @@ z2(struct lx *lx) lx_ungetc(lx, c); return lx->z(lx); case S2: /* e.g. "" */ - lx_ungetc(lx, c); return lx->z = z3, lx->z(lx); + lx_ungetc(lx, c); return lx->z = z5, lx->z(lx); default: ; /* unreached */ @@ -421,7 +608,7 @@ z2(struct lx *lx) default: if (lx->push != NULL) { - if (-1 == lx->push(lx->buf_opaque, c)) { + if (-1 == lx->push(lx->buf_opaque, (char)c)) { return TOK_ERROR; } } @@ -441,14 +628,14 @@ z2(struct lx *lx) } static enum lx_token -z3(struct lx *lx) +z5(struct lx *lx) { int c; enum { S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, - S20, NONE + S20, S21, S22, NONE } state; assert(lx != NULL); @@ -469,15 +656,14 @@ z3(struct lx *lx) switch (state) { case S0: /* start */ switch ((unsigned char) c) { - case '\t': - case '\n': - case '\r': - case ' ': state = S1; break; - case '"': state = S2; break; - case '#': state = S3; break; - case '\'': state = S4; break; - case ',': state = S5; break; - case '-': state = S6; break; + case ',': state = S1; break; + case ';': state = S2; break; + case '?': state = S3; break; + case '-': state = S4; break; + case '[': state = S5; break; + case '=': state = S6; break; + case 'e': state = S7; break; + case 's': state = S8; break; case '0': case '1': case '2': @@ -538,45 +724,41 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case ';': state = S8; break; - case '?': state = S9; break; - case 'e': state = S10; break; - case 's': state = S11; break; - default: lx->lgetc = NULL; return TOK_UNKNOWN; - } - break; - - case S1: /* e.g. "\\x09" */ - switch ((unsigned char) c) { + case 'z': state = S9; break; + case '\'': state = S10; break; + case '"': state = S11; break; + case '#': state = S12; break; case '\t': case '\n': case '\r': - case ' ': break; - default: lx_ungetc(lx, c); return lx->z(lx); + case ' ': state = S13; break; + default: lx->lgetc = NULL; return TOK_UNKNOWN; } break; - case S2: /* e.g. "\"" */ - lx_ungetc(lx, c); return lx->z = z1, lx->z(lx); - - case S3: /* e.g. "#" */ - lx_ungetc(lx, c); return lx->z = z2, lx->z(lx); + case S1: /* e.g. "," */ + lx_ungetc(lx, c); return TOK_COMMA; - case S4: /* e.g. "'" */ - lx_ungetc(lx, c); return lx->z = z0, lx->z(lx); + case S2: /* e.g. ";" */ + lx_ungetc(lx, c); return TOK_SEP; - case S5: /* e.g. "," */ - lx_ungetc(lx, c); return TOK_COMMA; + case S3: /* e.g. "?" */ + lx_ungetc(lx, c); return TOK_ANY; - case S6: /* e.g. "-" */ + case S4: /* e.g. "-" */ switch ((unsigned char) c) { - case '>': state = S20; break; + case '>': state = S22; break; default: lx->lgetc = NULL; return TOK_UNKNOWN; } break; - case S7: /* e.g. "a" */ + case S5: /* e.g. "[" */ + lx_ungetc(lx, c); return lx->z = z1, TOK_OPENENDIDS; + + case S6: /* e.g. "=" */ + lx_ungetc(lx, c); return TOK_EQUALS; + + case S7: /* e.g. "e" */ switch ((unsigned char) c) { case '0': case '1': @@ -628,7 +810,6 @@ z3(struct lx *lx) case 'k': case 'l': case 'm': - case 'n': case 'o': case 'p': case 'q': @@ -640,18 +821,13 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': break; + case 'z': state = S9; break; + case 'n': state = S19; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S8: /* e.g. ";" */ - lx_ungetc(lx, c); return TOK_SEP; - - case S9: /* e.g. "?" */ - lx_ungetc(lx, c); return TOK_ANY; - - case S10: /* e.g. "e" */ + case S8: /* e.g. "s" */ switch ((unsigned char) c) { case '0': case '1': @@ -703,24 +879,24 @@ z3(struct lx *lx) 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': state = S7; break; - case 'n': state = S17; break; + case 'z': state = S9; break; + case 't': state = S14; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S11: /* e.g. "s" */ + case S9: /* e.g. "a" */ switch ((unsigned char) c) { case '0': case '1': @@ -778,18 +954,37 @@ z3(struct lx *lx) case 'q': case 'r': case 's': + case 't': case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case 't': state = S12; break; + case 'z': break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S12: /* e.g. "st" */ + case S10: /* e.g. "'" */ + lx_ungetc(lx, c); return lx->z = z2, lx->z(lx); + + case S11: /* e.g. "\"" */ + lx_ungetc(lx, c); return lx->z = z3, lx->z(lx); + + case S12: /* e.g. "#" */ + lx_ungetc(lx, c); return lx->z = z4, lx->z(lx); + + case S13: /* e.g. "\\x09" */ + switch ((unsigned char) c) { + case '\t': + case '\n': + case '\r': + case ' ': break; + default: lx_ungetc(lx, c); return lx->z(lx); + } + break; + + case S14: /* e.g. "st" */ switch ((unsigned char) c) { case '0': case '1': @@ -852,13 +1047,13 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case 'a': state = S13; break; + case 'z': state = S9; break; + case 'a': state = S15; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S13: /* e.g. "sta" */ + case S15: /* e.g. "sta" */ switch ((unsigned char) c) { case '0': case '1': @@ -921,13 +1116,13 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case 'r': state = S14; break; + case 'z': state = S9; break; + case 'r': state = S16; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S14: /* e.g. "star" */ + case S16: /* e.g. "star" */ switch ((unsigned char) c) { case '0': case '1': @@ -990,13 +1185,13 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case 't': state = S15; break; + case 'z': state = S9; break; + case 't': state = S17; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S15: /* e.g. "start" */ + case S17: /* e.g. "start" */ switch ((unsigned char) c) { case '0': case '1': @@ -1060,16 +1255,16 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case ':': state = S16; break; + case 'z': state = S9; break; + case ':': state = S18; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S16: /* e.g. "start:" */ + case S18: /* e.g. "start:" */ lx_ungetc(lx, c); return TOK_START; - case S17: /* e.g. "en" */ + case S19: /* e.g. "en" */ switch ((unsigned char) c) { case '0': case '1': @@ -1132,13 +1327,13 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case 'd': state = S18; break; + case 'z': state = S9; break; + case 'd': state = S20; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S18: /* e.g. "end" */ + case S20: /* e.g. "end" */ switch ((unsigned char) c) { case '0': case '1': @@ -1202,16 +1397,16 @@ z3(struct lx *lx) case 'w': case 'x': case 'y': - case 'z': state = S7; break; - case ':': state = S19; break; + case 'z': state = S9; break; + case ':': state = S21; break; default: lx_ungetc(lx, c); return TOK_IDENT; } break; - case S19: /* e.g. "end:" */ + case S21: /* e.g. "end:" */ lx_ungetc(lx, c); return TOK_END; - case S20: /* e.g. "->" */ + case S22: /* e.g. "->" */ lx_ungetc(lx, c); return TOK_TO; default: @@ -1219,15 +1414,15 @@ z3(struct lx *lx) } switch (state) { - case S1: - case S2: - case S3: - case S4: + case S10: + case S11: + case S12: + case S13: break; default: if (lx->push != NULL) { - if (-1 == lx->push(lx->buf_opaque, c)) { + if (-1 == lx->push(lx->buf_opaque, (char)c)) { return TOK_ERROR; } } @@ -1240,25 +1435,27 @@ z3(struct lx *lx) switch (state) { case NONE: return TOK_EOF; - case S1: return TOK_EOF; - case S2: return TOK_EOF; - case S3: return TOK_EOF; - case S4: return TOK_EOF; - case S5: return TOK_COMMA; + case S1: return TOK_COMMA; + case S2: return TOK_SEP; + case S3: return TOK_ANY; + case S5: return TOK_OPENENDIDS; + case S6: return TOK_EQUALS; case S7: return TOK_IDENT; - case S8: return TOK_SEP; - case S9: return TOK_ANY; - case S10: return TOK_IDENT; - case S11: return TOK_IDENT; - case S12: return TOK_IDENT; - case S13: return TOK_IDENT; + case S8: return TOK_IDENT; + case S9: return TOK_IDENT; + case S10: return TOK_EOF; + case S11: return TOK_EOF; + case S12: return TOK_EOF; + case S13: return TOK_EOF; case S14: return TOK_IDENT; case S15: return TOK_IDENT; - case S16: return TOK_START; + case S16: return TOK_IDENT; case S17: return TOK_IDENT; - case S18: return TOK_IDENT; - case S19: return TOK_END; - case S20: return TOK_TO; + case S18: return TOK_START; + case S19: return TOK_IDENT; + case S20: return TOK_IDENT; + case S21: return TOK_END; + case S22: return TOK_TO; default: errno = EINVAL; return TOK_ERROR; } } @@ -1267,10 +1464,14 @@ const char * lx_name(enum lx_token t) { switch (t) { - case TOK_COMMA: return "COMMA"; case TOK_SEP: return "SEP"; case TOK_ANY: return "ANY"; case TOK_TO: return "TO"; + case TOK_ENDID: return "ENDID"; + case TOK_COMMA: return "COMMA"; + case TOK_CLOSEENDIDS: return "CLOSEENDIDS"; + case TOK_OPENENDIDS: return "OPENENDIDS"; + case TOK_EQUALS: return "EQUALS"; case TOK_IDENT: return "IDENT"; case TOK_END: return "END"; case TOK_START: return "START"; @@ -1293,10 +1494,14 @@ lx_example(enum lx_token (*z)(struct lx *), enum lx_token t) if (z == z0) { switch (t) { - case TOK_COMMA: return ""; case TOK_SEP: return ""; case TOK_ANY: return ""; case TOK_TO: return ""; + case TOK_ENDID: return ""; + case TOK_COMMA: return ""; + case TOK_CLOSEENDIDS: return ""; + case TOK_OPENENDIDS: return ""; + case TOK_EQUALS: return ""; case TOK_IDENT: return ""; case TOK_END: return ""; case TOK_START: return ""; @@ -1310,10 +1515,14 @@ lx_example(enum lx_token (*z)(struct lx *), enum lx_token t) } else if (z == z1) { switch (t) { - case TOK_COMMA: return ""; case TOK_SEP: return ""; case TOK_ANY: return ""; case TOK_TO: return ""; + case TOK_ENDID: return ""; + case TOK_COMMA: return ""; + case TOK_CLOSEENDIDS: return ""; + case TOK_OPENENDIDS: return ""; + case TOK_EQUALS: return ""; case TOK_IDENT: return ""; case TOK_END: return ""; case TOK_START: return ""; @@ -1327,10 +1536,14 @@ lx_example(enum lx_token (*z)(struct lx *), enum lx_token t) } else if (z == z2) { switch (t) { - case TOK_COMMA: return ""; case TOK_SEP: return ""; case TOK_ANY: return ""; case TOK_TO: return ""; + case TOK_ENDID: return ""; + case TOK_COMMA: return ""; + case TOK_CLOSEENDIDS: return ""; + case TOK_OPENENDIDS: return ""; + case TOK_EQUALS: return ""; case TOK_IDENT: return ""; case TOK_END: return ""; case TOK_START: return ""; @@ -1344,10 +1557,56 @@ lx_example(enum lx_token (*z)(struct lx *), enum lx_token t) } else if (z == z3) { switch (t) { + case TOK_SEP: return ""; + case TOK_ANY: return ""; + case TOK_TO: return ""; + case TOK_ENDID: return ""; case TOK_COMMA: return ""; + case TOK_CLOSEENDIDS: return ""; + case TOK_OPENENDIDS: return ""; + case TOK_EQUALS: return ""; + case TOK_IDENT: return ""; + case TOK_END: return ""; + case TOK_START: return ""; + case TOK_CHAR: return ""; + case TOK_HEX: return ""; + case TOK_OCT: return ""; + case TOK_ESC: return ""; + case TOK_LABEL: return ""; + default: goto error; + } + } else + if (z == z4) { + switch (t) { case TOK_SEP: return ""; case TOK_ANY: return ""; case TOK_TO: return ""; + case TOK_ENDID: return ""; + case TOK_COMMA: return ""; + case TOK_CLOSEENDIDS: return ""; + case TOK_OPENENDIDS: return ""; + case TOK_EQUALS: return ""; + case TOK_IDENT: return ""; + case TOK_END: return ""; + case TOK_START: return ""; + case TOK_CHAR: return ""; + case TOK_HEX: return ""; + case TOK_OCT: return ""; + case TOK_ESC: return ""; + case TOK_LABEL: return ""; + default: goto error; + } + } else + if (z == z5) { + switch (t) { + case TOK_SEP: return ""; + case TOK_ANY: return ""; + case TOK_TO: return ""; + case TOK_ENDID: return ""; + case TOK_COMMA: return ""; + case TOK_CLOSEENDIDS: return ""; + case TOK_OPENENDIDS: return ""; + case TOK_EQUALS: return ""; case TOK_IDENT: return ""; case TOK_END: return ""; case TOK_START: return ""; @@ -1376,7 +1635,7 @@ lx_init(struct lx *lx) *lx = lx_default; lx->c = EOF; - lx->z = z3; + lx->z = z5; lx->end.byte = 0; lx->end.line = 1; diff --git a/src/libfsm/lexer.h b/src/libfsm/lexer.h index 7848879fc..68e55b612 100644 --- a/src/libfsm/lexer.h +++ b/src/libfsm/lexer.h @@ -4,10 +4,14 @@ #define LX_H enum lx_token { - TOK_COMMA, TOK_SEP, TOK_ANY, TOK_TO, + TOK_ENDID, + TOK_COMMA, + TOK_CLOSEENDIDS, + TOK_OPENENDIDS, + TOK_EQUALS, TOK_IDENT, TOK_END, TOK_START, diff --git a/src/libfsm/lexer.lx b/src/libfsm/lexer.lx index 7aa8cf5bf..0288e1877 100644 --- a/src/libfsm/lexer.lx +++ b/src/libfsm/lexer.lx @@ -31,6 +31,17 @@ /[a-z0-9_]+/i -> $ident; +'=' -> $equals; +'[' -> $openendids .. ']' -> $closeendids { + /[\r\n\t ]+/; + "#" .. "\n"; + + ',' -> $comma; + + # using a lexical zone because $endid overlaps $ident + /[0-9]+/ -> $endid; +} + '->' -> $to; '?' -> $any; ';' -> $sep; diff --git a/src/libfsm/libfsm.syms b/src/libfsm/libfsm.syms index 6e1f72dbe..2801f3703 100644 --- a/src/libfsm/libfsm.syms +++ b/src/libfsm/libfsm.syms @@ -86,12 +86,12 @@ fsm_setstart fsm_getstart fsm_setend -fsm_getendidcount -fsm_getendids +fsm_endid_count +fsm_endid_get +fsm_endid_set fsm_setendid fsm_mapendids fsm_increndids -fsm_setendidstate fsm_countedges fsm_countstates diff --git a/src/libfsm/merge.c b/src/libfsm/merge.c index fd4d35ee5..69834a5bd 100644 --- a/src/libfsm/merge.c +++ b/src/libfsm/merge.c @@ -163,7 +163,6 @@ struct copy_end_ids_env { static int copy_end_ids_cb(fsm_state_t state, const fsm_end_id_t *ids, size_t num_ids, void *opaque) { - enum fsm_endid_set_res sres; struct copy_end_ids_env *env = opaque; assert(env->tag == 'M'); @@ -172,12 +171,8 @@ copy_end_ids_cb(fsm_state_t state, const fsm_end_id_t *ids, size_t num_ids, void state + env->base_src, id); #endif - sres = fsm_endid_set_bulk(env->dst, state + env->base_src, num_ids, ids, FSM_ENDID_BULK_REPLACE); - if (sres == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { - return 0; - } - - return 1; + return fsm_endid_set_bulk(env->dst, state + env->base_src, + num_ids, ids, FSM_ENDID_BULK_REPLACE); } static int diff --git a/src/libfsm/minimise.c b/src/libfsm/minimise.c index 94dfdf80b..8100e22da 100644 --- a/src/libfsm/minimise.c +++ b/src/libfsm/minimise.c @@ -951,33 +951,32 @@ static int collect_end_ids(const struct fsm *fsm, fsm_state_t s, struct end_metadata_end *e) { - e->count = fsm_getendidcount(fsm, s); + e->count = fsm_endid_count(fsm, s); + if (e->count == 0) { + return 1; + } - if (e->count > 0) { - e->ids = f_malloc(fsm->opt->alloc, - e->count * sizeof(e->ids[0])); - if (e->ids == NULL) { - return 0; - } + e->ids = f_malloc(fsm->opt->alloc, + e->count * sizeof(e->ids[0])); + if (e->ids == NULL) { + return 0; + } - size_t written; - enum fsm_getendids_res res = fsm_getendids(fsm, s, - e->count, e->ids, &written); - assert(res == FSM_GETENDIDS_FOUND); - assert(written == e->count); + int res = fsm_endid_get(fsm, s, e->count, e->ids); + assert(res == 1); - /* sort, to make comparison easier later */ - qsort(e->ids, e->count, - sizeof(e->ids[0]), cmp_end_ids); + /* sort, to make comparison easier later */ + qsort(e->ids, e->count, + sizeof(e->ids[0]), cmp_end_ids); #if LOG_ECS - fprintf(stderr, "%d:", s); - for (size_t i = 0; i < written; i++) { - fprintf(stderr, " %u", e->ids[i]); - } - fprintf(stderr, "\n"); -#endif + fprintf(stderr, "%d:", s); + for (size_t i = 0; i < written; i++) { + fprintf(stderr, " %u", e->ids[i]); } + fprintf(stderr, "\n"); +#endif + return 1; } diff --git a/src/libfsm/minimise_test_oracle.c b/src/libfsm/minimise_test_oracle.c index 9045ce67b..6cd1848c4 100644 --- a/src/libfsm/minimise_test_oracle.c +++ b/src/libfsm/minimise_test_oracle.c @@ -113,8 +113,8 @@ fsm_minimise_test_oracle(const struct fsm *fsm) unsigned *endid_group_assignments = NULL; size_t endid_group_count = 1; /* group 0 is the empty set */ unsigned *endid_group_leaders = NULL; - fsm_end_id_t *endid_buf_a = NULL; - fsm_end_id_t *endid_buf_b = NULL; + fsm_end_id_t *ids_a = NULL; + fsm_end_id_t *ids_b = NULL; table = calloc(row_words * table_states, sizeof(table[0])); if (table == NULL) { goto cleanup; } @@ -143,7 +143,7 @@ fsm_minimise_test_oracle(const struct fsm *fsm) * This includes the dead state. */ for (size_t i = 0; i < table_states; i++) { if (i < state_count && fsm_isend(fsm, i)) { - const size_t count = fsm_getendidcount(fsm, i); + const size_t count = fsm_endid_count(fsm, i); if (count > max_endid_count) { max_endid_count = count; } @@ -165,50 +165,56 @@ fsm_minimise_test_oracle(const struct fsm *fsm) } } - endid_buf_a = malloc(max_endid_count * sizeof(endid_buf_a[0])); - if (endid_buf_a == NULL) { goto cleanup; } - endid_buf_b = malloc(max_endid_count * sizeof(endid_buf_b[0])); - if (endid_buf_b == NULL) { goto cleanup; } + ids_a = malloc(max_endid_count * sizeof(ids_a[0])); + if (ids_a == NULL) { goto cleanup; } + ids_b = malloc(max_endid_count * sizeof(ids_b[0])); + if (ids_b == NULL) { goto cleanup; } /* For every end state, check if it has endids. If not, assign it * to endid group 0 (none). Otherwise, check if its endids match * any of the other end states. If so, assign it to the same endid * group, otherwise assign a new one and mark it as the leader. */ for (size_t i = 0; i < state_count; i++) { - if (fsm_isend(fsm, i)) { - size_t written_a; - enum fsm_getendids_res eres = fsm_getendids(fsm, i, - max_endid_count, endid_buf_a, &written_a); - assert(eres != FSM_GETENDIDS_ERROR_INSUFFICIENT_SPACE); - if (eres == FSM_GETENDIDS_NOT_FOUND) { - assert(written_a == 0); - } else { - assert(written_a > 0); - bool found = false; - /* note: skipping eg 0 here since that's the empty set */ - for (size_t eg_i = 1; eg_i < endid_group_count; eg_i++) { - size_t written_b; - eres = fsm_getendids(fsm, endid_group_leaders[eg_i], - max_endid_count, endid_buf_b, &written_b); - assert(eres != FSM_GETENDIDS_ERROR_INSUFFICIENT_SPACE); - if (written_b != written_a) { continue; } - if (0 == memcmp(endid_buf_a, endid_buf_b, written_a * sizeof(endid_buf_a[0]))) { - found = true; - endid_group_assignments[i] = eg_i; - break; - } else { - continue; - } - } + if (!fsm_isend(fsm, i)) { + endid_group_assignments[i] = 0; /* none */ + continue; + } - if (!found) { - endid_group_assignments[i] = endid_group_count; - endid_group_leaders[endid_group_count] = i; - endid_group_count++; - } + size_t count_a = fsm_endid_count(fsm, i); + assert(count_a <= max_endid_count); + if (count_a == 0) { + continue; + } + + int eres = fsm_endid_get(fsm, i, + count_a, ids_a); + assert(eres == 1); + + bool found = false; + /* note: skipping eg 0 here since that's the empty set */ + for (size_t eg_i = 1; eg_i < endid_group_count; eg_i++) { + size_t count_b = fsm_endid_count(fsm, endid_group_leaders[eg_i]); + if (count_b != count_a) { + continue; } - } else { - endid_group_assignments[i] = 0; /* none */ + + assert(count_b > 0); + assert(count_b <= max_endid_count); + eres = fsm_endid_get(fsm, endid_group_leaders[eg_i], + count_b, ids_b); + assert(eres == 1); + + if (0 == memcmp(ids_a, ids_b, count_a * sizeof(ids_a[0]))) { + found = true; + endid_group_assignments[i] = eg_i; + break; + } + } + + if (!found) { + endid_group_assignments[i] = endid_group_count; + endid_group_leaders[endid_group_count] = i; + endid_group_count++; } } @@ -355,8 +361,8 @@ fsm_minimise_test_oracle(const struct fsm *fsm) free(mapping); free(endid_group_assignments); free(endid_group_leaders); - free(endid_buf_a); - free(endid_buf_b); + free(ids_a); + free(ids_b); return res; @@ -366,8 +372,8 @@ fsm_minimise_test_oracle(const struct fsm *fsm) if (mapping != NULL) { free(mapping); } if (endid_group_assignments != NULL) { free(endid_group_assignments); } if (endid_group_leaders != NULL) { free(endid_group_leaders); } - if (endid_buf_a != NULL) { free(endid_buf_a); } - if (endid_buf_b != NULL) { free(endid_buf_b); } + if (ids_a != NULL) { free(ids_a); } + if (ids_b != NULL) { free(ids_b); } if (res != NULL) { fsm_free(res); } return NULL; } diff --git a/src/libfsm/parser.act b/src/libfsm/parser.act index 80ace7fdf..71ee0a89c 100644 --- a/src/libfsm/parser.act +++ b/src/libfsm/parser.act @@ -1,5 +1,5 @@ /* - * Copyright 2008-2017 Katherine Flavel + * Copyright 2008-2024 Katherine Flavel * * See LICENCE for the full copyright terms. */ @@ -22,6 +22,7 @@ char -> char; string -> string; state -> state; + endid -> endid; %header% @{ @@ -41,8 +42,9 @@ #include "lexer.h" #include "parser.h" - typedef char * string; - typedef fsm_state_t state; + typedef char * string; + typedef fsm_state_t state; + typedef fsm_end_id_t endid; struct act_statelist { char *id; @@ -194,12 +196,14 @@ if ((u == ULONG_MAX && errno == ERANGE) || u > UCHAR_MAX) { err(lex_state, "octal escape %s out of range: expected \\0..\\%o inclusive", lex_state->buf.a, UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } if ((u == ULONG_MAX && errno != 0) || *e != '\0') { err(lex_state, "%s: %s: expected \\0..\\%o inclusive", lex_state->buf.a, strerror(errno), UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } @@ -221,12 +225,14 @@ if ((u == ULONG_MAX && errno == ERANGE) || u > UCHAR_MAX) { err(lex_state, "hex escape %s out of range: expected \\x0..\\x%x inclusive", lex_state->buf.a, UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } if ((u == ULONG_MAX && errno != 0) || *e != '\0') { err(lex_state, "%s: %s: expected \\x0..\\x%x inclusive", lex_state->buf.a, strerror(errno), UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } @@ -245,6 +251,31 @@ @s = xstrdup(lex_state->buf.a); @}; + ENDID: () -> (id :endid) = @{ + unsigned long u; + char *e; + + errno = 0; + + u = strtoul(lex_state->buf.a, &e, 16); + + if ((u == ULONG_MAX && errno == ERANGE) || u > FSM_END_ID_MAX) { + err(lex_state, "end id %s out of range: expected 0..%u inclusive", + lex_state->buf.a, FSM_END_ID_MAX); + /* XXX: don't exit in library code */ + exit(EXIT_FAILURE); + } + + if ((u == ULONG_MAX && errno != 0) || *e != '\0') { + err(lex_state, "%s: %s: expected 0..%u inclusive", + lex_state->buf.a, strerror(errno), FSM_END_ID_MAX); + /* XXX: don't exit in library code */ + exit(EXIT_FAILURE); + } + + @id = (fsm_end_id_t) u; + @}; + %actions% : (n :string) -> (s :state) = @{ @@ -308,6 +339,12 @@ fsm_setend(fsm, @s, 1); @}; + : (s :state, id :endid) -> () = @{ + if (!fsm_endid_set(fsm, @s, @id)) { + @!; + } + @}; + : (s :string) -> () = @{ free(@s); @}; @@ -419,7 +456,19 @@ return NULL; } - ADVANCE_LEXER; /* XXX: what if the first token is unrecognised? */ + ADVANCE_LEXER; + switch (CURRENT_TERMINAL) { + case TOK_UNKNOWN: + /* fallthrough */ + case TOK_ERROR: + /* XXX: don't exit in library code */ + err(lex_state, "Syntax error"); + exit(EXIT_FAILURE); + + default: + break; + } + p_fsm(new, lex_state, act_state); free(act_state_s.states.buckets); diff --git a/src/libfsm/parser.c b/src/libfsm/parser.c index 19d5664f3..442449a44 100644 --- a/src/libfsm/parser.c +++ b/src/libfsm/parser.c @@ -9,7 +9,7 @@ /* BEGINNING OF HEADER */ -#line 151 "src/libfsm/parser.act" +#line 153 "src/libfsm/parser.act" #include @@ -28,8 +28,9 @@ #include "lexer.h" #include "parser.h" - typedef char * string; - typedef fsm_state_t state; + typedef char * string; + typedef fsm_state_t state; + typedef fsm_end_id_t endid; struct act_statelist { char *id; @@ -135,7 +136,7 @@ htab->longest_chain_length = max_chain_length; } -#line 139 "src/libfsm/parser.c" +#line 140 "src/libfsm/parser.c" #ifndef ERROR_TERMINAL @@ -146,13 +147,16 @@ static void p_label(fsm, lex_state, act_state, char *); static void p_items(fsm, lex_state, act_state); +static void p_xend_C_Cend_Hstates(fsm, lex_state, act_state); static void p_xstart(fsm, lex_state, act_state); static void p_xend(fsm, lex_state, act_state); -static void p_61(fsm, lex_state, act_state); -static void p_63(fsm, lex_state, act_state, string *); +static void p_xend_C_Cend_Hstate(fsm, lex_state, act_state, state *); extern void p_fsm(fsm, lex_state, act_state); -static void p_xend_C_Cend_Hids(fsm, lex_state, act_state); -static void p_xend_C_Cend_Hid(fsm, lex_state, act_state); +static void p_74(fsm, lex_state, act_state); +static void p_76(fsm, lex_state, act_state); +static void p_78(fsm, lex_state, act_state, string *); +static void p_xend_C_Cend_Hids(fsm, lex_state, act_state, state); +static void p_xend_C_Cend_Hid(fsm, lex_state, act_state, state); /* BEGINNING OF STATIC VARIABLES */ @@ -168,21 +172,21 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) return; } { - /* BEGINNING OF INLINE: 34 */ + /* BEGINNING OF INLINE: 40 */ { switch (CURRENT_TERMINAL) { case (TOK_CHAR): { /* BEGINNING OF EXTRACT: CHAR */ { -#line 240 "src/libfsm/parser.act" +#line 246 "src/libfsm/parser.act" assert(lex_state->buf.a[0] != '\0'); assert(lex_state->buf.a[1] == '\0'); ZIc = lex_state->buf.a[0]; -#line 186 "src/libfsm/parser.c" +#line 190 "src/libfsm/parser.c" } /* END OF EXTRACT: CHAR */ ADVANCE_LEXER; @@ -192,7 +196,7 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) { /* BEGINNING OF EXTRACT: ESC */ { -#line 168 "src/libfsm/parser.act" +#line 170 "src/libfsm/parser.act" assert(0 == strncmp(lex_state->buf.a, "\\", 1)); assert(2 == strlen(lex_state->buf.a)); @@ -210,7 +214,7 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) default: break; } -#line 214 "src/libfsm/parser.c" +#line 218 "src/libfsm/parser.c" } /* END OF EXTRACT: ESC */ ADVANCE_LEXER; @@ -220,7 +224,7 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) { /* BEGINNING OF EXTRACT: HEX */ { -#line 233 "src/libfsm/parser.act" +#line 239 "src/libfsm/parser.act" unsigned long u; char *e; @@ -236,18 +240,20 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) if ((u == ULONG_MAX && errno == ERANGE) || u > UCHAR_MAX) { err(lex_state, "hex escape %s out of range: expected \\x0..\\x%x inclusive", lex_state->buf.a, UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } if ((u == ULONG_MAX && errno != 0) || *e != '\0') { err(lex_state, "%s: %s: expected \\x0..\\x%x inclusive", lex_state->buf.a, strerror(errno), UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } ZIc = (char) (unsigned char) u; -#line 251 "src/libfsm/parser.c" +#line 257 "src/libfsm/parser.c" } /* END OF EXTRACT: HEX */ ADVANCE_LEXER; @@ -257,7 +263,7 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) { /* BEGINNING OF EXTRACT: OCT */ { -#line 206 "src/libfsm/parser.act" +#line 210 "src/libfsm/parser.act" unsigned long u; char *e; @@ -273,18 +279,20 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) if ((u == ULONG_MAX && errno == ERANGE) || u > UCHAR_MAX) { err(lex_state, "octal escape %s out of range: expected \\0..\\%o inclusive", lex_state->buf.a, UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } if ((u == ULONG_MAX && errno != 0) || *e != '\0') { err(lex_state, "%s: %s: expected \\0..\\%o inclusive", lex_state->buf.a, strerror(errno), UCHAR_MAX); + /* XXX: don't exit in library code */ exit(EXIT_FAILURE); } ZIc = (char) (unsigned char) u; -#line 288 "src/libfsm/parser.c" +#line 296 "src/libfsm/parser.c" } /* END OF EXTRACT: OCT */ ADVANCE_LEXER; @@ -294,7 +302,7 @@ p_label(fsm fsm, lex_state lex_state, act_state act_state, char *ZOc) goto ZL1; } } - /* END OF INLINE: 34 */ + /* END OF INLINE: 40 */ switch (CURRENT_TERMINAL) { case (TOK_LABEL): break; @@ -318,24 +326,24 @@ ZL2_items:; switch (CURRENT_TERMINAL) { case (TOK_IDENT): { - /* BEGINNING OF INLINE: 48 */ + /* BEGINNING OF INLINE: 54 */ { { string ZIa; - /* BEGINNING OF INLINE: id */ + /* BEGINNING OF INLINE: ident */ { { switch (CURRENT_TERMINAL) { case (TOK_IDENT): /* BEGINNING OF EXTRACT: IDENT */ { -#line 245 "src/libfsm/parser.act" +#line 251 "src/libfsm/parser.act" /* XXX: don't exit in library code */ ZIa = xstrdup(lex_state->buf.a); -#line 339 "src/libfsm/parser.c" +#line 347 "src/libfsm/parser.c" } /* END OF EXTRACT: IDENT */ break; @@ -345,15 +353,15 @@ ZL2_items:; ADVANCE_LEXER; } } - /* END OF INLINE: id */ - p_63 (fsm, lex_state, act_state, &ZIa); + /* END OF INLINE: ident */ + p_78 (fsm, lex_state, act_state, &ZIa); if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { RESTORE_LEXER; goto ZL1; } } } - /* END OF INLINE: 48 */ + /* END OF INLINE: 54 */ /* BEGINNING OF INLINE: items */ goto ZL2_items; /* END OF INLINE: items */ @@ -370,6 +378,92 @@ ZL1:; return; } +static void +p_xend_C_Cend_Hstates(fsm fsm, lex_state lex_state, act_state act_state) +{ + if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { + return; + } +ZL2_xend_C_Cend_Hstates:; + { + state ZIs; + + p_xend_C_Cend_Hstate (fsm, lex_state, act_state, &ZIs); + /* BEGINNING OF INLINE: 71 */ + { + switch (CURRENT_TERMINAL) { + case (TOK_EQUALS): + { + ADVANCE_LEXER; + switch (CURRENT_TERMINAL) { + case (TOK_OPENENDIDS): + break; + default: + goto ZL1; + } + ADVANCE_LEXER; + /* BEGINNING OF INLINE: 72 */ + { + switch (CURRENT_TERMINAL) { + case (TOK_ENDID): + { + p_xend_C_Cend_Hids (fsm, lex_state, act_state, ZIs); + if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { + RESTORE_LEXER; + goto ZL1; + } + } + break; + default: + break; + } + } + /* END OF INLINE: 72 */ + switch (CURRENT_TERMINAL) { + case (TOK_CLOSEENDIDS): + break; + default: + goto ZL1; + } + ADVANCE_LEXER; + } + break; + case (ERROR_TERMINAL): + RESTORE_LEXER; + goto ZL1; + default: + break; + } + } + /* END OF INLINE: 71 */ + /* BEGINNING OF INLINE: 73 */ + { + switch (CURRENT_TERMINAL) { + case (TOK_COMMA): + { + p_74 (fsm, lex_state, act_state); + /* BEGINNING OF INLINE: xend::end-states */ + if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { + RESTORE_LEXER; + goto ZL1; + } else { + goto ZL2_xend_C_Cend_Hstates; + } + /* END OF INLINE: xend::end-states */ + } + /*UNREACHED*/ + default: + break; + } + } + /* END OF INLINE: 73 */ + } + return; +ZL1:; + SAVE_LEXER ((ERROR_TERMINAL)); + return; +} + static void p_xstart(fsm fsm, lex_state lex_state, act_state act_state) { @@ -379,7 +473,7 @@ p_xstart(fsm fsm, lex_state lex_state, act_state act_state) string ZIn; state ZIs; - /* BEGINNING OF INLINE: 50 */ + /* BEGINNING OF INLINE: 56 */ { { switch (CURRENT_TERMINAL) { @@ -395,30 +489,30 @@ p_xstart(fsm fsm, lex_state lex_state, act_state act_state) { /* BEGINNING OF ACTION: err-expected-start */ { -#line 366 "src/libfsm/parser.act" +#line 403 "src/libfsm/parser.act" err_expected(lex_state, "'start:'"); -#line 403 "src/libfsm/parser.c" +#line 497 "src/libfsm/parser.c" } /* END OF ACTION: err-expected-start */ } ZL2:; } - /* END OF INLINE: 50 */ - /* BEGINNING OF INLINE: id */ + /* END OF INLINE: 56 */ + /* BEGINNING OF INLINE: ident */ { { switch (CURRENT_TERMINAL) { case (TOK_IDENT): /* BEGINNING OF EXTRACT: IDENT */ { -#line 245 "src/libfsm/parser.act" +#line 251 "src/libfsm/parser.act" /* XXX: don't exit in library code */ ZIn = xstrdup(lex_state->buf.a); -#line 422 "src/libfsm/parser.c" +#line 516 "src/libfsm/parser.c" } /* END OF EXTRACT: IDENT */ break; @@ -428,15 +522,15 @@ p_xstart(fsm fsm, lex_state lex_state, act_state act_state) ADVANCE_LEXER; } } - /* END OF INLINE: id */ - p_61 (fsm, lex_state, act_state); + /* END OF INLINE: ident */ + p_76 (fsm, lex_state, act_state); if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { RESTORE_LEXER; goto ZL1; } /* BEGINNING OF ACTION: add-state */ { -#line 252 "src/libfsm/parser.act" +#line 283 "src/libfsm/parser.act" struct act_statelist *p; const unsigned hash = hash_of_id((ZIn)); @@ -489,25 +583,25 @@ p_xstart(fsm fsm, lex_state lex_state, act_state act_state) act_state->states.buckets[bucket_id] = new; } -#line 493 "src/libfsm/parser.c" +#line 587 "src/libfsm/parser.c" } /* END OF ACTION: add-state */ /* BEGINNING OF ACTION: mark-start */ { -#line 304 "src/libfsm/parser.act" +#line 335 "src/libfsm/parser.act" fsm_setstart(fsm, (ZIs)); -#line 502 "src/libfsm/parser.c" +#line 596 "src/libfsm/parser.c" } /* END OF ACTION: mark-start */ /* BEGINNING OF ACTION: free */ { -#line 312 "src/libfsm/parser.act" +#line 349 "src/libfsm/parser.act" free((ZIn)); -#line 511 "src/libfsm/parser.c" +#line 605 "src/libfsm/parser.c" } /* END OF ACTION: free */ } @@ -529,7 +623,7 @@ p_xend(fsm fsm, lex_state lex_state, act_state act_state) switch (CURRENT_TERMINAL) { case (TOK_END): { - /* BEGINNING OF INLINE: 60 */ + /* BEGINNING OF INLINE: 75 */ { { switch (CURRENT_TERMINAL) { @@ -545,19 +639,19 @@ p_xend(fsm fsm, lex_state lex_state, act_state act_state) { /* BEGINNING OF ACTION: err-expected-end */ { -#line 370 "src/libfsm/parser.act" +#line 407 "src/libfsm/parser.act" err_expected(lex_state, "'end:'"); -#line 553 "src/libfsm/parser.c" +#line 647 "src/libfsm/parser.c" } /* END OF ACTION: err-expected-end */ } ZL2:; } - /* END OF INLINE: 60 */ - p_xend_C_Cend_Hids (fsm, lex_state, act_state); - p_61 (fsm, lex_state, act_state); + /* END OF INLINE: 75 */ + p_xend_C_Cend_Hstates (fsm, lex_state, act_state); + p_76 (fsm, lex_state, act_state); if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { RESTORE_LEXER; goto ZL1; @@ -576,7 +670,213 @@ ZL1:; } static void -p_61(fsm fsm, lex_state lex_state, act_state act_state) +p_xend_C_Cend_Hstate(fsm fsm, lex_state lex_state, act_state act_state, state *ZOs) +{ + state ZIs; + + if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { + return; + } + { + string ZIn; + + /* BEGINNING OF INLINE: ident */ + { + { + switch (CURRENT_TERMINAL) { + case (TOK_IDENT): + /* BEGINNING OF EXTRACT: IDENT */ + { +#line 251 "src/libfsm/parser.act" + + /* XXX: don't exit in library code */ + ZIn = xstrdup(lex_state->buf.a); + +#line 696 "src/libfsm/parser.c" + } + /* END OF EXTRACT: IDENT */ + break; + default: + goto ZL1; + } + ADVANCE_LEXER; + } + } + /* END OF INLINE: ident */ + /* BEGINNING OF ACTION: add-state */ + { +#line 283 "src/libfsm/parser.act" + + struct act_statelist *p; + const unsigned hash = hash_of_id((ZIn)); + const unsigned mask = act_state->states.bucket_count - 1; + size_t chain_length = 0; + unsigned bucket_id = hash & mask; + + assert((ZIn) != NULL); + + if (act_state->states.longest_chain_length > MAX_CHAIN_LENGTH) { + grow_state_hash_table(&act_state->states); + bucket_id = hash & (act_state->states.bucket_count - 1); + } + + for (p = act_state->states.buckets[bucket_id]; p != NULL; p = p->next) { + assert(p->id != NULL); + + chain_length++; + + if (0 == strcmp(p->id, (ZIn))) { + (ZIs) = p->state; + break; + } + } + + if (chain_length > act_state->states.longest_chain_length) { + act_state->states.longest_chain_length = chain_length; + } + + if (p == NULL) { + struct act_statelist *new; + + new = malloc(sizeof *new); + if (new == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + + /* XXX: don't exit in library code */ + new->id = xstrdup((ZIn)); + + if (!fsm_addstate(fsm, &(ZIs))) { + perror("fsm_addstate"); + exit(EXIT_FAILURE); + } + + new->state = (ZIs); + + new->next = act_state->states.buckets[bucket_id]; + act_state->states.buckets[bucket_id] = new; + } + +#line 762 "src/libfsm/parser.c" + } + /* END OF ACTION: add-state */ + /* BEGINNING OF ACTION: mark-end */ + { +#line 339 "src/libfsm/parser.act" + + fsm_setend(fsm, (ZIs), 1); + +#line 771 "src/libfsm/parser.c" + } + /* END OF ACTION: mark-end */ + /* BEGINNING OF ACTION: free */ + { +#line 349 "src/libfsm/parser.act" + + free((ZIn)); + +#line 780 "src/libfsm/parser.c" + } + /* END OF ACTION: free */ + } + goto ZL0; +ZL1:; + SAVE_LEXER ((ERROR_TERMINAL)); + return; +ZL0:; + *ZOs = ZIs; +} + +void +p_fsm(fsm fsm, lex_state lex_state, act_state act_state) +{ + if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { + return; + } + { + p_items (fsm, lex_state, act_state); + p_xstart (fsm, lex_state, act_state); + p_xend (fsm, lex_state, act_state); + switch (CURRENT_TERMINAL) { + case (TOK_EOF): + break; + case (ERROR_TERMINAL): + RESTORE_LEXER; + goto ZL1; + default: + goto ZL1; + } + ADVANCE_LEXER; + /* BEGINNING OF ACTION: free-statelist */ + { +#line 365 "src/libfsm/parser.act" + + struct act_statelist *p; + struct act_statelist *next; + unsigned b_i; /* bucket */ + + for (b_i = 0; b_i < act_state->states.bucket_count; b_i++) { + for (p = act_state->states.buckets[b_i]; p != NULL; p = next) { + next = p->next; + assert(p->id != NULL); + free(p->id); + free(p); + } + } + +#line 829 "src/libfsm/parser.c" + } + /* END OF ACTION: free-statelist */ + } + return; +ZL1:; + { + /* BEGINNING OF ACTION: err-syntax */ + { +#line 412 "src/libfsm/parser.act" + + err(lex_state, "Syntax error"); + exit(EXIT_FAILURE); + +#line 843 "src/libfsm/parser.c" + } + /* END OF ACTION: err-syntax */ + } +} + +static void +p_74(fsm fsm, lex_state lex_state, act_state act_state) +{ + if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { + return; + } + { + switch (CURRENT_TERMINAL) { + case (TOK_COMMA): + break; + default: + goto ZL1; + } + ADVANCE_LEXER; + } + return; +ZL1:; + { + /* BEGINNING OF ACTION: err-expected-comma */ + { +#line 399 "src/libfsm/parser.act" + + err_expected(lex_state, "','"); + +#line 873 "src/libfsm/parser.c" + } + /* END OF ACTION: err-expected-comma */ + } +} + +static void +p_76(fsm fsm, lex_state lex_state, act_state act_state) { if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { return; @@ -595,18 +895,18 @@ ZL1:; { /* BEGINNING OF ACTION: err-expected-sep */ { -#line 354 "src/libfsm/parser.act" +#line 391 "src/libfsm/parser.act" err_expected(lex_state, "';'"); -#line 603 "src/libfsm/parser.c" +#line 903 "src/libfsm/parser.c" } /* END OF ACTION: err-expected-sep */ } } static void -p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) +p_78(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) { switch (CURRENT_TERMINAL) { case (TOK_TO): @@ -616,19 +916,19 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) state ZIy; ADVANCE_LEXER; - /* BEGINNING OF INLINE: id */ + /* BEGINNING OF INLINE: ident */ { { switch (CURRENT_TERMINAL) { case (TOK_IDENT): /* BEGINNING OF EXTRACT: IDENT */ { -#line 245 "src/libfsm/parser.act" +#line 251 "src/libfsm/parser.act" /* XXX: don't exit in library code */ ZIb = xstrdup(lex_state->buf.a); -#line 632 "src/libfsm/parser.c" +#line 932 "src/libfsm/parser.c" } /* END OF EXTRACT: IDENT */ break; @@ -638,10 +938,10 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) ADVANCE_LEXER; } } - /* END OF INLINE: id */ + /* END OF INLINE: ident */ /* BEGINNING OF ACTION: add-state */ { -#line 252 "src/libfsm/parser.act" +#line 283 "src/libfsm/parser.act" struct act_statelist *p; const unsigned hash = hash_of_id((*ZIa)); @@ -694,12 +994,12 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) act_state->states.buckets[bucket_id] = new; } -#line 698 "src/libfsm/parser.c" +#line 998 "src/libfsm/parser.c" } /* END OF ACTION: add-state */ /* BEGINNING OF ACTION: add-state */ { -#line 252 "src/libfsm/parser.act" +#line 283 "src/libfsm/parser.act" struct act_statelist *p; const unsigned hash = hash_of_id((ZIb)); @@ -752,28 +1052,28 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) act_state->states.buckets[bucket_id] = new; } -#line 756 "src/libfsm/parser.c" +#line 1056 "src/libfsm/parser.c" } /* END OF ACTION: add-state */ /* BEGINNING OF ACTION: free */ { -#line 312 "src/libfsm/parser.act" +#line 349 "src/libfsm/parser.act" free((*ZIa)); -#line 765 "src/libfsm/parser.c" +#line 1065 "src/libfsm/parser.c" } /* END OF ACTION: free */ /* BEGINNING OF ACTION: free */ { -#line 312 "src/libfsm/parser.act" +#line 349 "src/libfsm/parser.act" free((ZIb)); -#line 774 "src/libfsm/parser.c" +#line 1074 "src/libfsm/parser.c" } /* END OF ACTION: free */ - /* BEGINNING OF INLINE: 42 */ + /* BEGINNING OF INLINE: 48 */ { switch (CURRENT_TERMINAL) { case (TOK_ANY): @@ -781,14 +1081,14 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) ADVANCE_LEXER; /* BEGINNING OF ACTION: add-edge-any */ { -#line 338 "src/libfsm/parser.act" +#line 375 "src/libfsm/parser.act" if (!fsm_addedge_any(fsm, (ZIx), (ZIy))) { perror("fsm_addedge_any"); exit(EXIT_FAILURE); } -#line 792 "src/libfsm/parser.c" +#line 1092 "src/libfsm/parser.c" } /* END OF ACTION: add-edge-any */ } @@ -804,14 +1104,14 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) } /* BEGINNING OF ACTION: add-edge-literal */ { -#line 331 "src/libfsm/parser.act" +#line 368 "src/libfsm/parser.act" if (!fsm_addedge_literal(fsm, (ZIx), (ZIy), (ZIc))) { perror("fsm_addedge_literal"); exit(EXIT_FAILURE); } -#line 815 "src/libfsm/parser.c" +#line 1115 "src/libfsm/parser.c" } /* END OF ACTION: add-edge-literal */ } @@ -820,14 +1120,14 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) { /* BEGINNING OF ACTION: add-edge-epsilon */ { -#line 345 "src/libfsm/parser.act" +#line 382 "src/libfsm/parser.act" if (!fsm_addedge_epsilon(fsm, (ZIx), (ZIy))) { perror("fsm_addedge_epsilon"); exit(EXIT_FAILURE); } -#line 831 "src/libfsm/parser.c" +#line 1131 "src/libfsm/parser.c" } /* END OF ACTION: add-edge-epsilon */ } @@ -838,18 +1138,18 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) { /* BEGINNING OF ACTION: err-expected-trans */ { -#line 358 "src/libfsm/parser.act" +#line 395 "src/libfsm/parser.act" err_expected(lex_state, "transition"); -#line 846 "src/libfsm/parser.c" +#line 1146 "src/libfsm/parser.c" } /* END OF ACTION: err-expected-trans */ } ZL3:; } - /* END OF INLINE: 42 */ - p_61 (fsm, lex_state, act_state); + /* END OF INLINE: 48 */ + p_76 (fsm, lex_state, act_state); if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { RESTORE_LEXER; goto ZL1; @@ -858,11 +1158,11 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) break; case (TOK_SEP): { - state ZI45; + state ZI51; /* BEGINNING OF ACTION: add-state */ { -#line 252 "src/libfsm/parser.act" +#line 283 "src/libfsm/parser.act" struct act_statelist *p; const unsigned hash = hash_of_id((*ZIa)); @@ -883,7 +1183,7 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) chain_length++; if (0 == strcmp(p->id, (*ZIa))) { - (ZI45) = p->state; + (ZI51) = p->state; break; } } @@ -904,30 +1204,30 @@ p_63(fsm fsm, lex_state lex_state, act_state act_state, string *ZIa) /* XXX: don't exit in library code */ new->id = xstrdup((*ZIa)); - if (!fsm_addstate(fsm, &(ZI45))) { + if (!fsm_addstate(fsm, &(ZI51))) { perror("fsm_addstate"); exit(EXIT_FAILURE); } - new->state = (ZI45); + new->state = (ZI51); new->next = act_state->states.buckets[bucket_id]; act_state->states.buckets[bucket_id] = new; } -#line 919 "src/libfsm/parser.c" +#line 1219 "src/libfsm/parser.c" } /* END OF ACTION: add-state */ /* BEGINNING OF ACTION: free */ { -#line 312 "src/libfsm/parser.act" +#line 349 "src/libfsm/parser.act" free((*ZIa)); -#line 928 "src/libfsm/parser.c" +#line 1228 "src/libfsm/parser.c" } /* END OF ACTION: free */ - p_61 (fsm, lex_state, act_state); + p_76 (fsm, lex_state, act_state); if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { RESTORE_LEXER; goto ZL1; @@ -945,106 +1245,28 @@ ZL1:; return; } -void -p_fsm(fsm fsm, lex_state lex_state, act_state act_state) -{ - if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { - return; - } - { - p_items (fsm, lex_state, act_state); - p_xstart (fsm, lex_state, act_state); - p_xend (fsm, lex_state, act_state); - switch (CURRENT_TERMINAL) { - case (TOK_EOF): - break; - case (ERROR_TERMINAL): - RESTORE_LEXER; - goto ZL1; - default: - goto ZL1; - } - ADVANCE_LEXER; - /* BEGINNING OF ACTION: free-statelist */ - { -#line 328 "src/libfsm/parser.act" - - struct act_statelist *p; - struct act_statelist *next; - unsigned b_i; /* bucket */ - - for (b_i = 0; b_i < act_state->states.bucket_count; b_i++) { - for (p = act_state->states.buckets[b_i]; p != NULL; p = next) { - next = p->next; - assert(p->id != NULL); - free(p->id); - free(p); - } - } - -#line 986 "src/libfsm/parser.c" - } - /* END OF ACTION: free-statelist */ - } - return; -ZL1:; - { - /* BEGINNING OF ACTION: err-syntax */ - { -#line 375 "src/libfsm/parser.act" - - err(lex_state, "Syntax error"); - exit(EXIT_FAILURE); - -#line 1000 "src/libfsm/parser.c" - } - /* END OF ACTION: err-syntax */ - } -} - static void -p_xend_C_Cend_Hids(fsm fsm, lex_state lex_state, act_state act_state) +p_xend_C_Cend_Hids(fsm fsm, lex_state lex_state, act_state act_state, state ZIs) { if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { return; } ZL2_xend_C_Cend_Hids:; { - p_xend_C_Cend_Hid (fsm, lex_state, act_state); - /* BEGINNING OF INLINE: 58 */ + p_xend_C_Cend_Hid (fsm, lex_state, act_state, ZIs); + /* BEGINNING OF INLINE: 65 */ { switch (CURRENT_TERMINAL) { case (TOK_COMMA): { - /* BEGINNING OF INLINE: 59 */ - { - { - switch (CURRENT_TERMINAL) { - case (TOK_COMMA): - break; - default: - goto ZL5; - } - ADVANCE_LEXER; - } - goto ZL4; - ZL5:; - { - /* BEGINNING OF ACTION: err-expected-comma */ - { -#line 362 "src/libfsm/parser.act" - - err_expected(lex_state, "','"); - -#line 1040 "src/libfsm/parser.c" - } - /* END OF ACTION: err-expected-comma */ - } - ZL4:; - } - /* END OF INLINE: 59 */ + p_74 (fsm, lex_state, act_state); /* BEGINNING OF INLINE: xend::end-ids */ - goto ZL2_xend_C_Cend_Hids; + if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { + RESTORE_LEXER; + goto ZL1; + } else { + goto ZL2_xend_C_Cend_Hids; + } /* END OF INLINE: xend::end-ids */ } /*UNREACHED*/ @@ -1055,7 +1277,7 @@ ZL2_xend_C_Cend_Hids:; break; } } - /* END OF INLINE: 58 */ + /* END OF INLINE: 65 */ } return; ZL1:; @@ -1064,114 +1286,62 @@ ZL1:; } static void -p_xend_C_Cend_Hid(fsm fsm, lex_state lex_state, act_state act_state) +p_xend_C_Cend_Hid(fsm fsm, lex_state lex_state, act_state act_state, state ZIs) { if ((CURRENT_TERMINAL) == (ERROR_TERMINAL)) { return; } { - string ZIn; - state ZIs; + endid ZIid; - /* BEGINNING OF INLINE: id */ - { + switch (CURRENT_TERMINAL) { + case (TOK_ENDID): + /* BEGINNING OF EXTRACT: ENDID */ { - switch (CURRENT_TERMINAL) { - case (TOK_IDENT): - /* BEGINNING OF EXTRACT: IDENT */ - { -#line 245 "src/libfsm/parser.act" +#line 276 "src/libfsm/parser.act" - /* XXX: don't exit in library code */ - ZIn = xstrdup(lex_state->buf.a); - -#line 1089 "src/libfsm/parser.c" - } - /* END OF EXTRACT: IDENT */ - break; - default: - goto ZL1; - } - ADVANCE_LEXER; - } - } - /* END OF INLINE: id */ - /* BEGINNING OF ACTION: add-state */ - { -#line 252 "src/libfsm/parser.act" - - struct act_statelist *p; - const unsigned hash = hash_of_id((ZIn)); - const unsigned mask = act_state->states.bucket_count - 1; - size_t chain_length = 0; - unsigned bucket_id = hash & mask; - - assert((ZIn) != NULL); - - if (act_state->states.longest_chain_length > MAX_CHAIN_LENGTH) { - grow_state_hash_table(&act_state->states); - bucket_id = hash & (act_state->states.bucket_count - 1); - } - - for (p = act_state->states.buckets[bucket_id]; p != NULL; p = p->next) { - assert(p->id != NULL); + unsigned long u; + char *e; - chain_length++; + errno = 0; - if (0 == strcmp(p->id, (ZIn))) { - (ZIs) = p->state; - break; - } - } + u = strtoul(lex_state->buf.a, &e, 16); - if (chain_length > act_state->states.longest_chain_length) { - act_state->states.longest_chain_length = chain_length; + if ((u == ULONG_MAX && errno == ERANGE) || u > FSM_END_ID_MAX) { + err(lex_state, "end id %s out of range: expected 0..%u inclusive", + lex_state->buf.a, FSM_END_ID_MAX); + /* XXX: don't exit in library code */ + exit(EXIT_FAILURE); } - if (p == NULL) { - struct act_statelist *new; - - new = malloc(sizeof *new); - if (new == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - + if ((u == ULONG_MAX && errno != 0) || *e != '\0') { + err(lex_state, "%s: %s: expected 0..%u inclusive", + lex_state->buf.a, strerror(errno), FSM_END_ID_MAX); /* XXX: don't exit in library code */ - new->id = xstrdup((ZIn)); - - if (!fsm_addstate(fsm, &(ZIs))) { - perror("fsm_addstate"); - exit(EXIT_FAILURE); - } - - new->state = (ZIs); - - new->next = act_state->states.buckets[bucket_id]; - act_state->states.buckets[bucket_id] = new; - } - -#line 1155 "src/libfsm/parser.c" + exit(EXIT_FAILURE); } - /* END OF ACTION: add-state */ - /* BEGINNING OF ACTION: mark-end */ - { -#line 308 "src/libfsm/parser.act" - fsm_setend(fsm, (ZIs), 1); + ZIid = (fsm_end_id_t) u; -#line 1164 "src/libfsm/parser.c" +#line 1327 "src/libfsm/parser.c" + } + /* END OF EXTRACT: ENDID */ + break; + default: + goto ZL1; } - /* END OF ACTION: mark-end */ - /* BEGINNING OF ACTION: free */ + ADVANCE_LEXER; + /* BEGINNING OF ACTION: mark-end-id */ { -#line 312 "src/libfsm/parser.act" +#line 343 "src/libfsm/parser.act" - free((ZIn)); + if (!fsm_endid_set(fsm, (ZIs), (ZIid))) { + goto ZL1; + } -#line 1173 "src/libfsm/parser.c" +#line 1343 "src/libfsm/parser.c" } - /* END OF ACTION: free */ + /* END OF ACTION: mark-end-id */ } return; ZL1:; @@ -1181,7 +1351,7 @@ ZL1:; /* BEGINNING OF TRAILER */ -#line 431 "src/libfsm/parser.act" +#line 480 "src/libfsm/parser.act" struct fsm *fsm_parse(FILE *f, const struct fsm_options *opt) { @@ -1227,7 +1397,19 @@ ZL1:; return NULL; } - ADVANCE_LEXER; /* XXX: what if the first token is unrecognised? */ + ADVANCE_LEXER; + switch (CURRENT_TERMINAL) { + case TOK_UNKNOWN: + /* fallthrough */ + case TOK_ERROR: + /* XXX: don't exit in library code */ + err(lex_state, "Syntax error"); + exit(EXIT_FAILURE); + + default: + break; + } + p_fsm(new, lex_state, act_state); free(act_state_s.states.buckets); @@ -1236,6 +1418,6 @@ ZL1:; return new; } -#line 1240 "src/libfsm/parser.c" +#line 1422 "src/libfsm/parser.c" /* END OF FILE */ diff --git a/src/libfsm/parser.h b/src/libfsm/parser.h index 70155c504..be8f288ec 100644 --- a/src/libfsm/parser.h +++ b/src/libfsm/parser.h @@ -9,7 +9,7 @@ /* BEGINNING OF HEADER */ -#line 160 "src/libfsm/parser.act" +#line 162 "src/libfsm/parser.act" typedef struct lex_state * lex_state; @@ -26,7 +26,7 @@ extern void p_fsm(fsm, lex_state, act_state); /* BEGINNING OF TRAILER */ -#line 432 "src/libfsm/parser.act" +#line 481 "src/libfsm/parser.act" #line 32 "src/libfsm/parser.h" diff --git a/src/libfsm/parser.sid b/src/libfsm/parser.sid index d1da43b30..7d22c7420 100644 --- a/src/libfsm/parser.sid +++ b/src/libfsm/parser.sid @@ -1,5 +1,5 @@ /* - * Copyright 2008-2017 Katherine Flavel + * Copyright 2008-2024 Katherine Flavel * * See LICENCE for the full copyright terms. */ @@ -9,10 +9,12 @@ char; string; state; + endid; %terminals% IDENT: () -> (:string); + ENDID: () -> (:endid); ESC: () -> (:char); OCT: () -> (:char); @@ -23,6 +25,10 @@ START; END; + OPENENDIDS; + CLOSEENDIDS; + + EQUALS; TO; ANY; SEP; @@ -36,6 +42,7 @@ : (:string) -> (:state); : (:state) -> (); : (:state) -> (); + : (:state, :endid) -> (); : (:string) -> (); ; @@ -64,14 +71,14 @@ LABEL; }; - id: () -> (n :string) = { + ident: () -> (n :string) = { n = IDENT; }; edge = { - a = id; + a = ident; TO; - b = id; + b = ident; x = (a); y = (b); @@ -106,7 +113,7 @@ * its own output. */ decl = { - a = id; + a = ident; ! = (a); @@ -137,7 +144,7 @@ ; }; - n = id; + n = ident; { SEP; @@ -155,8 +162,30 @@ xend [ - end-id = { - n = id; + end-id: (s :state) -> () = { + id = ENDID; + + (s, id); + }; + + end-ids: (s :state) -> () = { + end-id(s); + + { + { + COMMA; + ## + ; + }; + + end-ids(s); + || + $; + }; + }; + + end-state: () -> (s :state) = { + n = ident; s = (n); (s); @@ -164,8 +193,18 @@ (n); }; - end-ids = { - end-id; + end-states = { + s = end-state; + + { + EQUALS; + + OPENENDIDS; + { end-ids(s); || $; }; + CLOSEENDIDS; + || + $; + }; { { @@ -174,7 +213,7 @@ ; }; - end-ids; + end-states; || $; }; @@ -187,7 +226,7 @@ ; }; - end-ids; + end-states; { SEP; diff --git a/src/libfsm/print/api.c b/src/libfsm/print/api.c index 38e5dfc27..7a0a9ffa5 100644 --- a/src/libfsm/print/api.c +++ b/src/libfsm/print/api.c @@ -27,6 +27,19 @@ #include #include +/* TODO: centralise */ +static int +comp_end_id(const void *a, const void *b) +{ + assert(a != NULL); + assert(b != NULL); + + if (* (fsm_end_id_t *) a < * (fsm_end_id_t *) b) { return -1; } + if (* (fsm_end_id_t *) a > * (fsm_end_id_t *) b) { return +1; } + + return 0; +} + static int rangeclass(unsigned char x, unsigned char y) { @@ -90,10 +103,11 @@ fsm_print_api(FILE *f, const struct fsm *fsm_orig) fprintf(f, "\n"); fprintf(f, "#include \n"); + fprintf(f, "#include \n"); fprintf(f, "\n"); fprintf(f, "int\n"); - fprintf(f, "%sfsm(struct fsm *fsm, struct fsm_state *x, struct fsm_state *y)\n", + fprintf(f, "%sfsm(struct fsm *fsm, fsm_state_t *x, fsm_state_t *y)\n", fsm->opt->prefix != NULL ? fsm->opt->prefix : ""); fprintf(f, "{\n"); @@ -103,16 +117,20 @@ fsm_print_api(FILE *f, const struct fsm *fsm_orig) fprintf(f, "\tsize_t i;\n"); fprintf(f, "\n"); + fprintf(f, "\tassert(x != NULL);\n"); + fprintf(f, "\tassert(y != NULL);\n"); + fprintf(f, "\n"); + fprintf(f, "\tfor (i = 0; i < %zu; i++) {\n", fsm->statecount); fprintf(f, "\t\tif (i == %u) {\n", start); - fprintf(f, "\t\t\ts[%u] = x;\n", start); + fprintf(f, "\t\t\ts[%u] = *x;\n", start); fprintf(f, "\t\t\tcontinue;\n"); fprintf(f, "\t\t}\n"); fprintf(f, "\n"); fprintf(f, "\t\tif (i == %u) {\n", end); - fprintf(f, "\t\t\ts[%u] = y;\n", end); + fprintf(f, "\t\t\ts[%u] = *y;\n", end); fprintf(f, "\t\t\tcontinue;\n"); fprintf(f, "\t\t}\n"); fprintf(f, "\n"); @@ -124,6 +142,38 @@ fsm_print_api(FILE *f, const struct fsm *fsm_orig) fprintf(f, "\t}\n"); fprintf(f, "\n"); + /* endleaf() doesn't make sense for this format */ + + { + size_t count; + + count = fsm_endid_count(fsm, end); + if (count > 0) { + fsm_end_id_t *ids; + int res; + + ids = f_malloc(fsm->opt->alloc, count * sizeof *ids); + if (ids == NULL) { + /* XXX */ + goto error; + } + + res = fsm_endid_get(fsm, end, count, ids); + assert(res == 1); + + qsort(ids, count, sizeof *ids, comp_end_id); + + fprintf(f, "\tif (fsm_isend(fsm, s[%u])) {\n", end); + for (size_t id = 0; id < count; id++) { + fprintf(f, "\t\tif (!fsm_endid_set(fsm, s[%u], %zu)) { return 0; }\n", end, id); + } + fprintf(f, "\t}\n"); + fprintf(f, "\n"); + + f_free(fsm->opt->alloc, ids); + } + } + a = f_malloc(fsm->opt->alloc, fsm->statecount * sizeof *a); if (a == NULL) { /* XXX */ diff --git a/src/libfsm/print/awk.c b/src/libfsm/print/awk.c index b71ffc307..462a3ab7f 100644 --- a/src/libfsm/print/awk.c +++ b/src/libfsm/print/awk.c @@ -32,13 +32,14 @@ #define START UINT32_MAX static int -leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) +leaf(FILE *f, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque) { assert(f != NULL); assert(leaf_opaque == NULL); (void) leaf_opaque; (void) ids; + (void) count; /* XXX: this should be FSM_UNKNOWN or something non-EOF, * maybe user defined */ @@ -91,17 +92,37 @@ static int print_end(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, enum dfavm_op_end end_bits, const struct ir *ir) { + (void) ir; + if (end_bits == VM_END_FAIL) { fprintf(f, "return -1"); return 0; } if (opt->endleaf != NULL) { - if (-1 == opt->endleaf(f, op->ir_state->end_ids, opt->endleaf_opaque)) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { return -1; } } else { - fprintf(f, "return %td", op->ir_state - ir->states); + size_t i; + + assert(f != NULL); + + /* awk can't return an array */ + fprintf(f, "return \""); + + for (i = 0; i < op->ir_state->endids.count; i++) { + fprintf(f, "%u", op->ir_state->endids.ids[i]); + + if (i < op->ir_state->endids.count - 1) { + fprintf(f, ","); + } + } + + fprintf(f, "\""); } return 0; @@ -125,14 +146,18 @@ print_branch(FILE *f, const struct dfavm_op_ir *op, const char *prefix) static int fsm_print_awkfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *cp, const char *prefix, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *leaf_opaque) { static const struct dfavm_assembler_ir zero; struct dfavm_assembler_ir a; struct dfavm_op_ir *op; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; assert(f != NULL); assert(ir != NULL); diff --git a/src/libfsm/print/c.c b/src/libfsm/print/c.c index dbca1d3fa..00e71adb1 100644 --- a/src/libfsm/print/c.c +++ b/src/libfsm/print/c.c @@ -53,12 +53,13 @@ ir_hasend(const struct ir *ir) } static int -leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) +leaf(FILE *f, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque) { assert(f != NULL); assert(leaf_opaque == NULL); (void) ids; + (void) count; (void) leaf_opaque; /* XXX: this should be FSM_UNKNOWN or something non-EOF, @@ -136,7 +137,7 @@ static int print_singlecase(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *cp, struct ir_state *cs, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *leaf_opaque) { assert(ir != NULL); @@ -149,7 +150,7 @@ print_singlecase(FILE *f, const struct ir *ir, const struct fsm_options *opt, switch (cs->strategy) { case IR_NONE: fprintf(f, "\t\t\t"); - if (-1 == leaf(f, cs->end_ids, leaf_opaque)) { + if (-1 == leaf(f, cs->endids.ids, cs->endids.count, leaf_opaque)) { return -1; } fprintf(f, "\n"); @@ -178,7 +179,7 @@ print_singlecase(FILE *f, const struct ir *ir, const struct fsm_options *opt, print_groups(f, opt, ir_indexof(ir, cs), cs->u.partial.groups, cs->u.partial.n); fprintf(f, "\t\t\tdefault: "); - if (-1 == leaf(f, cs->end_ids, leaf_opaque)) { + if (-1 == leaf(f, cs->endids.ids, cs->endids.count, leaf_opaque)) { return -1; } fprintf(f, "\n"); @@ -209,7 +210,7 @@ print_singlecase(FILE *f, const struct ir *ir, const struct fsm_options *opt, print_ranges(f, opt, cs->u.error.error.ranges, cs->u.error.error.n); fprintf(f, " "); - if (-1 == leaf(f, cs->end_ids, leaf_opaque)) { + if (-1 == leaf(f, cs->endids.ids, cs->endids.count, leaf_opaque)) { return -1; } fprintf(f, "\n"); @@ -288,13 +289,18 @@ endstates(FILE *f, const struct fsm_options *opt, const struct ir *ir) } fprintf(f, "\tcase S%u: ", i); + if (opt->endleaf != NULL) { - if (-1 == opt->endleaf(f, ir->states[i].end_ids, opt->endleaf_opaque)) { + if (-1 == opt->endleaf(f, + ir->states[i].endids.ids, ir->states[i].endids.count, + opt->endleaf_opaque)) + { return -1; } } else { fprintf(f, "return %u;", i); } + fprintf(f, "\n"); } fprintf(f, "\tdefault: return -1; /* unexpected EOT */\n"); @@ -306,7 +312,7 @@ endstates(FILE *f, const struct fsm_options *opt, const struct ir *ir) int fsm_print_cfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *cp, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *leaf_opaque) { unsigned i; @@ -377,7 +383,7 @@ fsm_print_c_body(FILE *f, const struct ir *ir, const struct fsm_options *opt) switch (opt->io) { case FSM_IO_GETC: - fprintf(f, "\twhile (c = fsm_getc(opaque), c != EOF) {\n"); + fprintf(f, "\twhile (c = fsm_getc(getc_opaque), c != EOF) {\n"); break; case FSM_IO_STR: @@ -425,9 +431,8 @@ fsm_print_c_complete(FILE *f, const struct ir *ir, switch (opt->io) { case FSM_IO_GETC: - fprintf(f, "(int (*fsm_getc)(void *opaque), void *opaque)\n"); + fprintf(f, "(int (*fsm_getc)(void *getc_opaque), void *getc_opaque)\n"); fprintf(f, "{\n"); - fprintf(f, "\t(void)opaque;\n"); if (ir->n > 0) { fprintf(f, "\tint c;\n"); fprintf(f, "\n"); @@ -435,9 +440,8 @@ fsm_print_c_complete(FILE *f, const struct ir *ir, break; case FSM_IO_STR: - fprintf(f, "(const char *s, void *opaque)\n"); + fprintf(f, "(const char *s)\n"); fprintf(f, "{\n"); - fprintf(f, "\t(void)opaque;\n"); if (ir->n > 0) { fprintf(f, "\tconst char *p;\n"); fprintf(f, "\n"); @@ -445,9 +449,8 @@ fsm_print_c_complete(FILE *f, const struct ir *ir, break; case FSM_IO_PAIR: - fprintf(f, "(const char *b, const char *e, void *opaque)\n"); + fprintf(f, "(const char *b, const char *e)\n"); fprintf(f, "{\n"); - fprintf(f, "\t(void)opaque;\n"); if (ir->n > 0) { fprintf(f, "\tconst char *p;\n"); fprintf(f, "\n"); diff --git a/src/libfsm/print/dot.c b/src/libfsm/print/dot.c index 25f6ea4a7..54d151a96 100644 --- a/src/libfsm/print/dot.c +++ b/src/libfsm/print/dot.c @@ -37,16 +37,6 @@ singlestate(FILE *f, const struct fsm *fsm, fsm_state_t s) assert(fsm->opt != NULL); assert(s < fsm->statecount); - if (!fsm->opt->anonymous_states) { - fprintf(f, "\t%sS%-2u [ label = <", - fsm->opt->prefix != NULL ? fsm->opt->prefix : "", - s); - - fprintf(f, "%u", s); - - fprintf(f, "> ];\n"); - } - if (!fsm->opt->consolidate_edges) { { struct state_iter jt; @@ -163,45 +153,73 @@ singlestate(FILE *f, const struct fsm *fsm, fsm_state_t s) static int print_dotfrag(FILE *f, const struct fsm *fsm) { - fsm_state_t i; + fsm_state_t s; assert(f != NULL); assert(fsm != NULL); assert(fsm->opt != NULL); - for (i = 0; i < fsm->statecount; i++) { - if (fsm_isend(fsm, i)) { - enum fsm_getendids_res res; - size_t written; - struct fsm_end_ids *ids = NULL; - const size_t count = fsm_getendidcount(fsm, i); + for (s = 0; s < fsm->statecount; s++) { + if (!fsm_isend(fsm, s)) { + if (!fsm->opt->anonymous_states) { + fprintf(f, "\t%sS%-2u [ label = <%u> ];\n", + fsm->opt->prefix != NULL ? fsm->opt->prefix : "", + s, s); + } + } else { + fsm_end_id_t *ids; + size_t count; + + ids = NULL; + count = fsm_endid_count(fsm, s); if (count > 0) { - ids = f_malloc(fsm->opt->alloc, - sizeof(*ids) + ((count - 1) * sizeof(ids->ids))); - assert(ids != NULL); + int res; + + ids = f_malloc(fsm->opt->alloc, count * sizeof *ids); if (ids == NULL) { return -1; } - res = fsm_getendids(fsm, i, count, - ids->ids, &written); - if (res == FSM_GETENDIDS_FOUND) { - ids->count = (unsigned)written; - } else { - assert(res == FSM_GETENDIDS_NOT_FOUND); - } + res = fsm_endid_get(fsm, s, count, ids); + assert(res == 1); } fprintf(f, "\t%sS%-2u [ shape = doublecircle", - fsm->opt->prefix != NULL ? fsm->opt->prefix : "", i); + fsm->opt->prefix != NULL ? fsm->opt->prefix : "", s); + + assert(f != NULL); + + fprintf(f, ", "); + + fprintf(f, "label = <"); if (fsm->opt->endleaf != NULL) { - fprintf(f, ", "); - if (-1 == fsm->opt->endleaf(f, ids, fsm->opt->endleaf_opaque)) { + if (-1 == fsm->opt->endleaf(f, + ids, count, + fsm->opt->endleaf_opaque)) + { return -1; } + } else if (!fsm->opt->anonymous_states) { + fprintf(f, "%u", s); + } + + if (fsm->opt->endleaf != NULL || !fsm->opt->anonymous_states) { + if (count > 0) { + fprintf(f, "
"); + } } + for (size_t i = 0; i < count; i++) { + fprintf(f, "#%u", ids[i]); + + if (i < count - 1) { + fprintf(f, ","); + } + } + + fprintf(f, ">"); + fprintf(f, " ];\n"); f_free(fsm->opt->alloc, ids); @@ -209,7 +227,7 @@ print_dotfrag(FILE *f, const struct fsm *fsm) /* TODO: show example here, unless !opt->comments */ - if (-1 == singlestate(f, fsm, i)) { + if (-1 == singlestate(f, fsm, s)) { return -1; } } diff --git a/src/libfsm/print/fsm.c b/src/libfsm/print/fsm.c index ea41ea757..46bc428ff 100644 --- a/src/libfsm/print/fsm.c +++ b/src/libfsm/print/fsm.c @@ -24,6 +24,19 @@ #include #include +/* TODO: centralise */ +static int +comp_end_id(const void *a, const void *b) +{ + assert(a != NULL); + assert(b != NULL); + + if (* (fsm_end_id_t *) a < * (fsm_end_id_t *) b) { return -1; } + if (* (fsm_end_id_t *) a > * (fsm_end_id_t *) b) { return +1; } + + return 0; +} + /* TODO: centralise */ static int findany(const struct fsm *fsm, fsm_state_t state, fsm_state_t *a) @@ -278,11 +291,58 @@ fsm_print_fsm(FILE *f, const struct fsm *fsm) fprintf(f, "end: "); for (s = 0; s < fsm->statecount; s++) { - if (fsm_isend(fsm, s)) { - end--; + fsm_end_id_t *ids; + size_t count; + + if (!fsm_isend(fsm, s)) { + continue; + } + + end--; + + count = fsm_endid_count(fsm, s); + if (count > 0) { + int res; + + ids = f_malloc(fsm->opt->alloc, count * sizeof *ids); + if (ids == NULL) { + return -1; + } - fprintf(f, "%u%s", s, end > 0 ? ", " : ";\n"); + res = fsm_endid_get(fsm, s, count, ids); + assert(res == 1); } + + if (fsm->opt->endleaf != NULL) { + if (-1 == fsm->opt->endleaf(f, + ids, count, + fsm->opt->endleaf_opaque)) + { + return -1; + } + } else { + fprintf(f, "%u", s); + } + + if (count > 0) { + qsort(ids, count, sizeof *ids, comp_end_id); + + fprintf(f, " = ["); + + for (size_t id = 0; id < count; id++) { + fprintf(f, "%zu", id); + + if (id + 1 < count) { + fprintf(f, ", "); + } + } + + fprintf(f, "]"); + + f_free(fsm->opt->alloc, ids); + } + + fprintf(f, "%s", end > 0 ? ", " : ";\n"); } done: diff --git a/src/libfsm/print/go.c b/src/libfsm/print/go.c index d0a4edc47..7b3616f9d 100644 --- a/src/libfsm/print/go.c +++ b/src/libfsm/print/go.c @@ -29,12 +29,13 @@ #include "ir.h" static int -leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) +leaf(FILE *f, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque) { assert(f != NULL); assert(leaf_opaque == NULL); (void) ids; + (void) count; (void) leaf_opaque; /* XXX: this should be FSM_UNKNOWN or something non-EOF, @@ -97,14 +98,22 @@ print_end(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, return 0; } + fprintf(f, "{\n"); + fprintf(f, "\t\t"); + if (opt->endleaf != NULL) { - if (-1 == opt->endleaf(f, op->ir_state->end_ids, opt->endleaf_opaque)) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { return -1; } } else { - fprintf(f, "{\n\t\treturn %td\n\t}\n", op->ir_state - ir->states); + fprintf(f, "return %td", op->ir_state - ir->states); } + fprintf(f, "\n\t}\n"); + return 0; } @@ -132,14 +141,18 @@ print_fetch(FILE *f, const struct fsm_options *opt) static int fsm_print_gofrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *cp, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *leaf_opaque) { static const struct dfavm_assembler_ir zero; struct dfavm_assembler_ir a; struct dfavm_op_ir *op; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; assert(f != NULL); assert(ir != NULL); diff --git a/src/libfsm/print/ir.c b/src/libfsm/print/ir.c index 3a7aee222..f23ce238a 100644 --- a/src/libfsm/print/ir.c +++ b/src/libfsm/print/ir.c @@ -467,26 +467,30 @@ make_ir(const struct fsm *fsm) assert(i < ir->n); ir->states[i].isend = fsm_isend(fsm, i); - ir->states[i].end_ids = NULL; + ir->states[i].endids.ids = NULL; + ir->states[i].endids.count = 0; + if (fsm_isend(fsm, i)) { - enum fsm_getendids_res res; - size_t written; - const size_t count = fsm_getendidcount(fsm, i); - struct fsm_end_ids *ids = f_malloc(fsm->opt->alloc, - sizeof(*ids) + (count == 0 ? 0 : (count - 1) * sizeof(ids->ids[0]))); - if (ids == NULL) { - goto error; - } + fsm_end_id_t *ids; + size_t count; - res = fsm_getendids(fsm, i, count, - ids->ids, &written); - if (res == FSM_GETENDIDS_FOUND) { - ids->count = (unsigned)written; - ir->states[i].end_ids = ids; + count = fsm_endid_count(fsm, i); + if (count == 0) { + ids = NULL; } else { - assert(res == FSM_GETENDIDS_NOT_FOUND); - f_free(fsm->opt->alloc, ids); + int res; + + ids = f_malloc(fsm->opt->alloc, count * sizeof *ids); + if (ids == NULL) { + goto error; + } + + res = fsm_endid_get(fsm, i, count, ids); + assert(res == 1); } + + ir->states[i].endids.ids = ids; + ir->states[i].endids.count = count; } if (make_state(fsm, i, &ir->states[i]) == -1) { @@ -593,8 +597,7 @@ free_ir(const struct fsm *fsm, struct ir *ir) for (i = 0; i < ir->n; i++) { f_free(fsm->opt->alloc, (void *) ir->states[i].example); - - f_free(fsm->opt->alloc, (void *) ir->states[i].end_ids); + f_free(fsm->opt->alloc, (void *) ir->states[i].endids.ids); switch (ir->states[i].strategy) { case IR_TABLE: diff --git a/src/libfsm/print/ir.h b/src/libfsm/print/ir.h index f9f5c40c3..05ad758e7 100644 --- a/src/libfsm/print/ir.h +++ b/src/libfsm/print/ir.h @@ -53,7 +53,10 @@ struct ir_state { const char *example; unsigned int isend:1; - struct fsm_end_ids *end_ids; /* NULL -> 0 */ + struct { + fsm_end_id_t *ids; /* NULL -> 0 */ + size_t count; + } endids; enum ir_strategy strategy; union { diff --git a/src/libfsm/print/irdot.c b/src/libfsm/print/irdot.c index 206a42e5e..8e91029ca 100644 --- a/src/libfsm/print/irdot.c +++ b/src/libfsm/print/irdot.c @@ -173,7 +173,7 @@ print_grouplinks(FILE *f, unsigned self, } } -static void +static int print_cs(FILE *f, const struct fsm_options *opt, const struct ir *ir, const struct ir_state *cs) { @@ -188,9 +188,24 @@ print_cs(FILE *f, const struct fsm_options *opt, fprintf(f, "\tcs%u [ label =\n", ir_indexof(ir, cs)); fprintf(f, "\t\t<\n"); + fprintf(f, "\t\t \n", ir_indexof(ir, cs), strategy_name(cs->strategy)); + if (cs->isend && cs->endids.count > 0) { + fprintf(f, "\t\t \n"); + } + if (cs->example != NULL) { fprintf(f, "\t\t \n"); + } + switch (cs->strategy) { case IR_NONE: break; @@ -290,6 +317,8 @@ print_cs(FILE *f, const struct fsm_options *opt, default: ; } + + return 0; } int @@ -320,7 +349,9 @@ fsm_print_ir(FILE *f, const struct fsm *fsm) } for (i = 0; i < ir->n; i++) { - print_cs(f, fsm->opt, ir, &ir->states[i]); + if (-1 == print_cs(f, fsm->opt, ir, &ir->states[i])) { + return -1; + } } fprintf(f, "}\n"); diff --git a/src/libfsm/print/irjson.c b/src/libfsm/print/irjson.c index 173bef0df..189d4b571 100644 --- a/src/libfsm/print/irjson.c +++ b/src/libfsm/print/irjson.c @@ -112,7 +112,7 @@ print_groups(FILE *f, const struct fsm_options *opt, fprintf(f, "\t\t\t]\n"); } -static void +static int print_cs(FILE *f, const struct fsm_options *opt, const struct ir_state *cs) { @@ -123,6 +123,30 @@ print_cs(FILE *f, const struct fsm_options *opt, fprintf(f, "\t\t{\n"); fprintf(f, "\t\t\t\"end\": %s,\n", cs->isend ? "true" : "false"); + if (cs->isend && cs->endids.count > 0) { + fprintf(f, "\t\t\t\"end_id\": ["); + for (size_t i = 0; i < cs->endids.count; i++) { + fprintf(f, "%u", cs->endids.ids[i]); + + if (i < cs->endids.count - 1) { + fprintf(f, ", "); + } + } + fprintf(f, "],\n"); + } + + /* showing endleaf in addition to existing content */ + if (cs->isend && opt->endleaf != NULL) { + fprintf(f, "\t\t\t\"endleaf\": "); + if (-1 == opt->endleaf(f, + cs->endids.ids, cs->endids.count, + opt->endleaf_opaque)) + { + return -1; + } + fprintf(f, ",\n"); + } + fprintf(f, "\t\t\t\"strategy\": \"%s\"", strategy_name(cs->strategy)); if (cs->example != NULL || cs->strategy != IR_NONE) { fprintf(f, ","); @@ -183,6 +207,8 @@ print_cs(FILE *f, const struct fsm_options *opt, } fprintf(f, "\t\t}"); + + return 0; } int @@ -205,7 +231,9 @@ fsm_print_irjson(FILE *f, const struct fsm *fsm) fprintf(f, "\t\"states\": [\n"); for (i = 0; i < ir->n; i++) { - print_cs(f, fsm->opt, &ir->states[i]); + if (-1 == print_cs(f, fsm->opt, &ir->states[i])) { + return -1; + } if (i + 1 < ir->n) { fprintf(f, ","); diff --git a/src/libfsm/print/json.c b/src/libfsm/print/json.c index 5c3235237..11c7a5f24 100644 --- a/src/libfsm/print/json.c +++ b/src/libfsm/print/json.c @@ -184,6 +184,8 @@ singlestate(FILE *f, const struct fsm *fsm, fsm_state_t s, int *notfirst) print_edge_bitmap(f, notfirst, fsm->opt, s, e.state, &bm); } + state_set_free(unique); + /* * Special edges are not consolidated above */ @@ -237,6 +239,7 @@ fsm_print_json(FILE *f, const struct fsm *fsm) fprintf(f, " ],\n"); } + /* showing endleaf in addition to existing content */ if (fsm->opt->endleaf != NULL) { int notfirst; @@ -244,37 +247,42 @@ fsm_print_json(FILE *f, const struct fsm *fsm) fprintf(f, " \"endleaf\": [ "); for (i = 0; i < fsm->statecount; i++) { - if (fsm_isend(fsm, i)) { - enum fsm_getendids_res res; - size_t written; - const size_t count = fsm_getendidcount(fsm, i); - struct fsm_end_ids *ids = f_malloc(fsm->opt->alloc, - sizeof(*ids) + ((count - 1) * sizeof(ids->ids[0]))); - assert(ids != NULL); - - res = fsm_getendids(fsm, i, count, - ids->ids, &written); - if (res == FSM_GETENDIDS_FOUND) { - ids->count = (unsigned)written; - } else { - assert(res == FSM_GETENDIDS_NOT_FOUND); - ids->count = 0; - } + fsm_end_id_t *ids; + size_t count; + int res; - if (notfirst) { - fprintf(f, ", "); - } + if (!fsm_isend(fsm, i)) { + continue; + } + + count = fsm_endid_count(fsm, i); - fprintf(f, "{ %u, ", i); + ids = f_malloc(fsm->opt->alloc, count * sizeof *ids); + if (ids == NULL) { + return -1; + } - fsm->opt->endleaf(f, ids, fsm->opt->endleaf_opaque); + res = fsm_endid_get(fsm, i, count, ids); + assert(res == 1); - fprintf(f, " }"); + if (notfirst) { + fprintf(f, ", "); + } - f_free(fsm->opt->alloc, ids); + fprintf(f, "{ %u, ", i); - notfirst = 1; + if (-1 == fsm->opt->endleaf(f, + ids, count, + fsm->opt->endleaf_opaque)) + { + return -1; } + + fprintf(f, " }"); + + f_free(fsm->opt->alloc, ids); + + notfirst = 1; } fprintf(f, " ],\n"); } diff --git a/src/libfsm/print/rust.c b/src/libfsm/print/rust.c index e249c6aad..af2b0f302 100644 --- a/src/libfsm/print/rust.c +++ b/src/libfsm/print/rust.c @@ -32,12 +32,13 @@ #define START UINT32_MAX static int -leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) +leaf(FILE *f, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque) { assert(f != NULL); assert(leaf_opaque == NULL); (void) ids; + (void) count; (void) leaf_opaque; /* XXX: this should be FSM_UNKNOWN or something non-EOF, @@ -109,7 +110,10 @@ print_end(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, } if (opt->endleaf != NULL) { - if (-1 == opt->endleaf(f, op->ir_state->end_ids, opt->endleaf_opaque)) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { return -1; } } else { @@ -144,7 +148,7 @@ static int fsm_print_rustfrag(FILE *f, const struct dfavm_assembler_ir *a, const struct ir *ir, const struct fsm_options *opt, const char *cp, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *leaf_opaque) { struct dfavm_op_ir *op; @@ -362,9 +366,14 @@ fsm_print_rust_complete(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *prefix, const char *cp) { static const struct dfavm_assembler_ir zero; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; struct dfavm_assembler_ir a; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; + assert(f != NULL); assert(ir != NULL); assert(opt != NULL); diff --git a/src/libfsm/print/sh.c b/src/libfsm/print/sh.c index 7b6bee8d2..04e84663e 100644 --- a/src/libfsm/print/sh.c +++ b/src/libfsm/print/sh.c @@ -127,7 +127,10 @@ print_end(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, } if (opt->endleaf != NULL) { - if (-1 == opt->endleaf(f, op->ir_state->end_ids, opt->endleaf_opaque)) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { return -1; } } else { @@ -156,7 +159,11 @@ fsm_print_shfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt) struct dfavm_assembler_ir a; struct dfavm_op_ir *op; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; assert(f != NULL); assert(ir != NULL); diff --git a/src/libfsm/print/vmasm.c b/src/libfsm/print/vmasm.c index 8e3085b86..046610c44 100644 --- a/src/libfsm/print/vmasm.c +++ b/src/libfsm/print/vmasm.c @@ -171,7 +171,18 @@ print_asm_amd64(FILE *f, const char *prefix, break; } + + /* endleaf in addition to existing instructions */ + if (opt->endleaf != NULL) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { + return -1; + } + } } else { + /* TODO: we don't have a way to override the -1 (or its API) */ switch (dialect) { case AMD64_ATT: fprintf(f, "\tmovl $-1, %%%s\n", ret_reg); @@ -372,7 +383,11 @@ print_vmasm_encoding(FILE *f, const struct fsm *fsm, enum asm_dialect dialect) static const struct dfavm_assembler_ir zero; struct dfavm_assembler_ir a; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; assert(f != NULL); assert(fsm != NULL); diff --git a/src/libfsm/print/vmc.c b/src/libfsm/print/vmc.c index 911619a7f..f94cee60d 100644 --- a/src/libfsm/print/vmc.c +++ b/src/libfsm/print/vmc.c @@ -29,12 +29,13 @@ #include "ir.h" static int -leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) +leaf(FILE *f, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque) { assert(f != NULL); assert(leaf_opaque == NULL); (void) ids; + (void) count; (void) leaf_opaque; /* XXX: this should be FSM_UNKNOWN or something non-EOF, @@ -96,7 +97,10 @@ print_end(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, } if (opt->endleaf != NULL) { - if (-1 == opt->endleaf(f, op->ir_state->end_ids, opt->endleaf_opaque)) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { return -1; } } else { @@ -121,7 +125,7 @@ print_fetch(FILE *f, const struct fsm_options *opt) * Per its API, fsm_getc() is expected to return a positive character * value (as if cast via unsigned char), or EOF. Just like fgetc() does. */ - fprintf(f, "if (c = fsm_getc(opaque), c == EOF) "); + fprintf(f, "if (c = fsm_getc(getc_opaque), c == EOF) "); break; case FSM_IO_STR: @@ -279,14 +283,18 @@ walk_sequence(struct dfavm_op_ir *op, static int fsm_print_cfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *cp, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *leaf_opaque) { static const struct dfavm_assembler_ir zero; struct dfavm_assembler_ir a; struct dfavm_op_ir *op; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; assert(f != NULL); assert(ir != NULL); @@ -467,20 +475,18 @@ fsm_print_c_complete(FILE *f, const struct ir *ir, const struct fsm_options *opt switch (opt->io) { case FSM_IO_GETC: - fprintf(f, "(int (*fsm_getc)(void *opaque), void *opaque)\n"); + fprintf(f, "(int (*fsm_getc)(void *opaque), void *getc_opaque)\n"); fprintf(f, "{\n"); break; case FSM_IO_STR: - fprintf(f, "(const char *s, void *opaque)\n"); + fprintf(f, "(const char *s)\n"); fprintf(f, "{\n"); - fprintf(f, "\t(void)opaque;\n"); break; case FSM_IO_PAIR: - fprintf(f, "(const char *b, const char *e, void *opaque)\n"); + fprintf(f, "(const char *b, const char *e)\n"); fprintf(f, "{\n"); - fprintf(f, "\t(void)opaque;\n"); break; } diff --git a/src/libfsm/print/vmdot.c b/src/libfsm/print/vmdot.c index 101934f17..bdcb2e3de 100644 --- a/src/libfsm/print/vmdot.c +++ b/src/libfsm/print/vmdot.c @@ -92,11 +92,26 @@ print_end(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, } if (opt->endleaf != NULL) { - if (-1 == opt->endleaf(f, op->ir_state->end_ids, opt->endleaf_opaque)) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { return -1; } } else { fprintf(f, "ret %td", op->ir_state - ir->states); + + if (op->ir_state->endids.count > 0) { + fprintf(f, " / "); + + for (size_t i = 0; i < op->ir_state->endids.count; i++) { + fprintf(f, "#%u", op->ir_state->endids.ids[i]); + + if (i < op->ir_state->endids.count - 1) { + fprintf(f, " "); + } + } + } } return 0; @@ -288,7 +303,11 @@ fsm_print_vmdotfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt) static const struct dfavm_assembler_ir zero; struct dfavm_assembler_ir a; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; assert(f != NULL); assert(ir != NULL); diff --git a/src/libfsm/print/vmops.c b/src/libfsm/print/vmops.c index 7804d3cd9..11972ffa5 100644 --- a/src/libfsm/print/vmops.c +++ b/src/libfsm/print/vmops.c @@ -35,12 +35,13 @@ enum vmops_dialect { }; static int -leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) +leaf(FILE *f, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque) { assert(f != NULL); assert(leaf_opaque == NULL); (void) ids; + (void) count; (void) leaf_opaque; /* XXX: this should be FSM_UNKNOWN or something non-EOF, @@ -97,7 +98,7 @@ print_cond(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, } static int -print_end(FILE *f, const struct dfavm_op_ir *op, const char *prefix, +print_end(FILE *f, const struct dfavm_op_ir *op, const struct fsm_options *opt, const char *prefix, enum dfavm_op_end end_bits, const struct ir *ir) { if (end_bits == VM_END_FAIL) { @@ -105,7 +106,18 @@ print_end(FILE *f, const struct dfavm_op_ir *op, const char *prefix, return 0; } - fprintf(f, "%sactionRET, %td},\n", prefix, op->ir_state - ir->states); + if (opt->endleaf != NULL) { + if (-1 == opt->endleaf(f, + op->ir_state->endids.ids, op->ir_state->endids.count, + opt->endleaf_opaque)) + { + return -1; + } + } else { + fprintf(f, "%sactionRET, %td", prefix, op->ir_state - ir->states); + } + + fprintf(f, "},\n"); return 0; } @@ -137,14 +149,18 @@ print_fetch(FILE *f, const struct fsm_options *opt, const char *prefix) /* TODO: eventually to be non-static */ static int fsm_print_vmopsfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *prefix, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *leaf_opaque) { static const struct dfavm_assembler_ir zero; struct dfavm_assembler_ir a; struct dfavm_op_ir *op; - static const struct fsm_vm_compile_opts vm_opts = { FSM_VM_COMPILE_DEFAULT_FLAGS, FSM_VM_COMPILE_VM_V1, NULL }; + static const struct fsm_vm_compile_opts vm_opts = { + FSM_VM_COMPILE_DEFAULT_FLAGS, + FSM_VM_COMPILE_VM_V1, + NULL + }; assert(f != NULL); assert(ir != NULL); @@ -172,7 +188,7 @@ fsm_print_vmopsfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, if (-1 == print_cond(f, op, opt, prefix)) { return -1; } - if (-1 == print_end(f, op, prefix, op->u.stop.end_bits, ir)) { + if (-1 == print_end(f, op, opt, prefix, op->u.stop.end_bits, ir)) { return -1; } break; @@ -181,7 +197,7 @@ fsm_print_vmopsfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, if (-1 == print_fetch(f, opt, prefix)) { return -1; } - if (-1 == print_end(f, op, prefix, op->u.fetch.end_bits, ir)) { + if (-1 == print_end(f, op, opt, prefix, op->u.fetch.end_bits, ir)) { return -1; } break; diff --git a/src/libfsm/walk2.c b/src/libfsm/walk2.c index c321db678..afd8107ca 100644 --- a/src/libfsm/walk2.c +++ b/src/libfsm/walk2.c @@ -263,67 +263,60 @@ fsm_walk2_tuple_new(struct fsm_walk2_data *data, } if (is_end) { - size_t num_a_endids = 0, num_b_endids = 0, total_num_endids; + size_t count_a = 0, count_b = 0, count_total; if (fsm_a != NULL && fsm_isend(fsm_a,a)) { - num_a_endids = fsm_getendidcount(fsm_a, a); + count_a = fsm_endid_count(fsm_a, a); } if (fsm_b != NULL && fsm_isend(fsm_b,b)) { - num_b_endids = fsm_getendidcount(fsm_b, b); + count_b = fsm_endid_count(fsm_b, b); } - total_num_endids = num_a_endids + num_b_endids; + count_total = count_a + count_b; - if (total_num_endids > 0) { - fsm_end_id_t *endids= NULL; - enum fsm_getendids_res ret; + if (count_total > 0) { + const struct fsm_alloc *alloc; + fsm_end_id_t *ids; + int ret; - endids = calloc(total_num_endids, sizeof endids[0]); - if (endids == NULL) { + if (fsm_a != NULL) { + alloc = fsm_a->opt->alloc; + } else if (fsm_b != NULL) { + alloc = fsm_b->opt->alloc; + } else { + assert(!"unreached"); + } + + ids = f_malloc(alloc, count_total * sizeof *ids); + if (ids == NULL) { return NULL; } - if (num_a_endids > 0) { - size_t nwritten = 0; - ret = fsm_getendids(fsm_a, a, num_a_endids, &endids[0], &nwritten); + if (count_a > 0) { + ret = fsm_endid_get(fsm_a, a, count_a, ids); + assert(ret == 1); + } - if (ret != FSM_GETENDIDS_FOUND || nwritten != num_a_endids) { - free(endids); - errno = (ret != FSM_GETENDIDS_FOUND) ? ENOENT : EINVAL; - return NULL; - } + if (count_b > 0) { + ret = fsm_endid_get(fsm_b, b, count_b, ids + count_a); + assert(ret == 1); } - if (num_b_endids > 0) { - size_t nwritten = 0; - ret = fsm_getendids(fsm_b, b, num_b_endids, &endids[num_a_endids], &nwritten); + ret = fsm_endid_set_bulk( + data->new, + p->comb, + count_total, + &ids[0], + FSM_ENDID_BULK_REPLACE); - if (ret != FSM_GETENDIDS_FOUND || nwritten != num_b_endids) { - free(endids); - errno = (ret != FSM_GETENDIDS_FOUND) ? ENOENT : EINVAL; - return NULL; - } - } + f_free(alloc, ids); - { - enum fsm_endid_set_res ret; - - ret = fsm_endid_set_bulk( - data->new, - p->comb, - total_num_endids, - &endids[0], - FSM_ENDID_BULK_REPLACE); - if (ret == FSM_ENDID_SET_ERROR_ALLOC_FAIL) { - int errsv = errno; - free(endids); - errno = errsv; - return NULL; - } + if (!ret) { + int errsv = errno; + errno = errsv; + return NULL; } - - free(endids); } } diff --git a/src/libre/ac.c b/src/libre/ac.c index efe13df36..e9412602e 100644 --- a/src/libre/ac.c +++ b/src/libre/ac.c @@ -332,8 +332,7 @@ trie_to_fsm_state(struct trie_state *ts, struct fsm *fsm, fsm_state_t state; state_set_reset(ts->endids, &si); while (state_set_next(&si, &state)) { - fsm_end_id_t endid = (fsm_end_id_t)state; - if (!fsm_setendidstate(fsm, st, endid)) { + if (!fsm_endid_set(fsm, st, (fsm_end_id_t) state)) { return 0; } } diff --git a/src/lx/ast.c b/src/lx/ast.c index 75754f58d..5852c7055 100644 --- a/src/lx/ast.c +++ b/src/lx/ast.c @@ -9,8 +9,10 @@ #include #include #include +#include #include +#include #include @@ -233,50 +235,39 @@ ast_getendmappingbyendid(fsm_end_id_t id) struct ast_mapping * ast_getendmapping(const struct fsm *fsm, fsm_state_t s) { - #define ID_STACK_BUF_COUNT 4 - size_t id_count; - fsm_end_id_t *id_buf_dynamic = NULL; - fsm_end_id_t id_buf[ID_STACK_BUF_COUNT]; - enum fsm_getendids_res res; - size_t written; + fsm_end_id_t *ids; + size_t count; struct ast_mapping *m; + int res; - id_count = fsm_getendidcount(fsm, s); - if (id_count > ID_STACK_BUF_COUNT) { - id_buf_dynamic = malloc(id_count * sizeof(id_buf_dynamic[0])); - if (id_buf_dynamic == NULL) { - return NULL; - } + if (!fsm_isend(fsm, s)) { + errno = EINVAL; + return NULL; } - res = fsm_getendids(fsm, - s, id_count, - id_buf_dynamic == NULL ? id_buf : id_buf_dynamic, - &written); - if (res == FSM_GETENDIDS_NOT_FOUND) { - if (id_buf_dynamic != NULL) { - free(id_buf_dynamic); - } + count = fsm_endid_count(fsm, s); + if (count == 0) { + errno = EINVAL; return NULL; } - /* Should always have an appropriately sized buffer, - * or fail to allocate above */ - assert(res != FSM_GETENDIDS_ERROR_INSUFFICIENT_SPACE); + ids = malloc(count * sizeof *ids); + if (ids == NULL) { + return NULL; + } - assert(res == FSM_GETENDIDS_FOUND); - assert(written == id_count); - assert(written > 0); + res = fsm_endid_get(fsm, s, count, ids); + assert(res == 1); - m = ast_getendmappingbyendid(id_buf[0]); + m = ast_getendmappingbyendid(ids[0]); if (LOG()) { fprintf(stderr, "ast_getendmapping: got mapping %p mappings[%d]\n", - (void *)m, id_buf[0]); + (void *) m, ids[0]); } - if (id_buf_dynamic != NULL) { - free(id_buf_dynamic); - } + free(ids); + return m; } + diff --git a/src/lx/print/c.c b/src/lx/print/c.c index 6308ba0c1..a8ae67eec 100644 --- a/src/lx/print/c.c +++ b/src/lx/print/c.c @@ -29,7 +29,7 @@ int fsm_print_cfrag(FILE *f, const struct ir *ir, const struct fsm_options *opt, const char *cp, - int (*leaf)(FILE *, const struct fsm_end_ids *ids, const void *leaf_opaque), + int (*leaf)(FILE *, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque), const void *opaque); static int @@ -138,7 +138,7 @@ shortest_example(const struct fsm *fsm, const struct ast_token *token, } static int -leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) +leaf(FILE *f, const fsm_end_id_t *ids, size_t count, const void *leaf_opaque) { const struct ast *ast; const struct ast_mapping *m; @@ -150,8 +150,8 @@ leaf(FILE *f, const struct fsm_end_ids *ids, const void *leaf_opaque) if (ids == NULL) { m = NULL; } else { - assert(ids->count > 0); - m = ast_getendmappingbyendid(ids->ids[0]); + assert(count > 0); + m = ast_getendmappingbyendid(ids[0]); } if (m == NULL) { diff --git a/src/lx/print/dot.c b/src/lx/print/dot.c index 4904c246c..5ad9d6212 100644 --- a/src/lx/print/dot.c +++ b/src/lx/print/dot.c @@ -65,7 +65,7 @@ mapping(FILE *f, const struct ast_mapping *m, const struct ast *ast) } static int -endleaf_dot(FILE *f, const struct fsm_end_ids *end_ids, +endleaf_dot(FILE *f, const fsm_end_id_t *ids, size_t count, const void *endleaf_opaque) { const struct ast_mapping *m; @@ -74,9 +74,9 @@ endleaf_dot(FILE *f, const struct fsm_end_ids *end_ids, assert(f != NULL); assert(endleaf_opaque != NULL); - (void)end_ids; /* TODO */ - assert(end_ids->count > 0); - m = ast_getendmappingbyendid(end_ids->ids[0]); + assert(ids != NULL); + assert(count > 0); + m = ast_getendmappingbyendid(ids[0]); ast = endleaf_opaque; diff --git a/src/re/main.c b/src/re/main.c index 77f147518..ea2c68ae8 100644 --- a/src/re/main.c +++ b/src/re/main.c @@ -30,6 +30,8 @@ #include +#include + #include "libfsm/internal.h" /* XXX */ #include "libre/print.h" /* XXX */ #include "libre/class.h" /* XXX */ @@ -49,7 +51,7 @@ */ struct match { - fsm_end_id_t i; + fsm_end_id_t id; const char *s; struct match *next; }; @@ -274,7 +276,7 @@ find_match_with_id(fsm_end_id_t id) struct matches_list *res = all_matches; while (res != NULL) { struct match *m = res->head; - if (m->i == id) { + if (m->id == id) { return m; } res = res->next; @@ -285,39 +287,40 @@ find_match_with_id(fsm_end_id_t id) static struct match * find_first_match_for_end_state(const struct fsm *dfa, fsm_state_t s) { -#define MAX_END_IDS 8 /* FIXME: what is reasonable here? */ - fsm_end_id_t end_id_buf[MAX_END_IDS]; - size_t end_ids_written; - enum fsm_getendids_res res; + fsm_end_id_t *ids, id; + size_t count; + int res; if (!fsm_isend(dfa, s)) { return NULL; } - res = fsm_getendids(dfa, s, MAX_END_IDS, - end_id_buf, &end_ids_written); - if (res == FSM_GETENDIDS_ERROR_INSUFFICIENT_SPACE) { - fprintf(stderr, "Error: Multiple end IDs\n"); - return NULL; - } else if (res == FSM_GETENDIDS_NOT_FOUND) { + count = fsm_endid_count(dfa, s); + if (count == 0) { return NULL; - } else { - assert(res == FSM_GETENDIDS_FOUND); - /* continues below */ } - return find_match_with_id(end_id_buf[0]); + ids = xmalloc(count * sizeof *ids); + + res = fsm_endid_get(dfa, s, count, ids); + assert(res == 1); + + id = ids[0]; + + free(ids); + + return find_match_with_id(id); } static struct match * -addmatch(struct match **head, int i, const char *s) +addmatch(struct match **head, fsm_end_id_t id, const char *s) { struct match *new; assert(head != NULL); assert(s != NULL); - if ((1U << i) > INT_MAX) { + if ((1U << id) > INT_MAX) { fprintf(stderr, "Too many patterns for int bitmap\n"); exit(EXIT_FAILURE); } @@ -337,12 +340,9 @@ addmatch(struct match **head, int i, const char *s) } } - new = malloc(sizeof *new); - if (new == NULL) { - return NULL; - } + new = xmalloc(sizeof *new); - new->i = i; + new->id = id; new->s = s; new->next = *head; @@ -360,11 +360,7 @@ add_matches_list(struct match *head) return; } - new = malloc(sizeof *new); - if (new == NULL) { - perror("allocating matches list"); - abort(); - } + new = xmalloc(sizeof *new); new->next = all_matches; new->head = head; @@ -416,12 +412,13 @@ printexample(FILE *f, const struct fsm *fsm, fsm_state_t state) } static int -endleaf_c(FILE *f, const struct fsm_end_ids *end_ids, - const void *endleaf_opaque) +endleaf_c(FILE *f, + const fsm_end_id_t *ids, size_t count, + const void *endleaf_opaque) { const struct match *m; - int n; - size_t i, end_ids_count; + unsigned n; + size_t i; assert(endleaf_opaque == NULL); @@ -430,11 +427,9 @@ endleaf_c(FILE *f, const struct fsm_end_ids *end_ids, n = 0; - end_ids_count = (end_ids == NULL ? 0 : end_ids->count); - - for (i = 0; i < end_ids_count; i++) { - for (m = find_match_with_id(end_ids->ids[i]); m != NULL; m = m->next) { - n |= 1 << m->i; + for (i = 0; i < count; i++) { + for (m = find_match_with_id(ids[i]); m != NULL; m = m->next) { + n |= 1U << m->id; } } @@ -442,11 +437,11 @@ endleaf_c(FILE *f, const struct fsm_end_ids *end_ids, fprintf(f, " /* "); - for (i = 0; i < end_ids_count; i++) { - for (m = find_match_with_id(end_ids->ids[i]); m != NULL; m = m->next) { + for (i = 0; i < count; i++) { + for (m = find_match_with_id(ids[i]); m != NULL; m = m->next) { fprintf(f, "\"%s\"", m->s); /* XXX: escape string (and comment) */ - if (m->next != NULL || i < end_ids_count - 1) { + if (m->next != NULL || i < count - 1) { fprintf(f, ", "); } } @@ -458,12 +453,13 @@ endleaf_c(FILE *f, const struct fsm_end_ids *end_ids, } static int -endleaf_rust(FILE *f, const struct fsm_end_ids *end_ids, - const void *endleaf_opaque) +endleaf_rust(FILE *f, + const fsm_end_id_t *ids, size_t count, + const void *endleaf_opaque) { const struct match *m; - int n; - size_t i, end_ids_count; + unsigned n; + size_t i; assert(endleaf_opaque == NULL); @@ -472,11 +468,9 @@ endleaf_rust(FILE *f, const struct fsm_end_ids *end_ids, n = 0; - end_ids_count = (end_ids == NULL ? 0 : end_ids->count); - - for (i = 0; i < end_ids_count; i++) { - for (m = find_match_with_id(end_ids->ids[i]); m != NULL; m = m->next) { - n |= 1 << m->i; + for (i = 0; i < count; i++) { + for (m = find_match_with_id(ids[i]); m != NULL; m = m->next) { + n |= 1U << m->id; } } @@ -484,11 +478,11 @@ endleaf_rust(FILE *f, const struct fsm_end_ids *end_ids, fprintf(f, " /* "); - for (i = 0; i < end_ids_count; i++) { - for (m = find_match_with_id(end_ids->ids[i]); m != NULL; m = m->next) { + for (i = 0; i < count; i++) { + for (m = find_match_with_id(ids[i]); m != NULL; m = m->next) { fprintf(f, "\"%s\"", m->s); /* XXX: escape string (and comment) */ - if (m->next != NULL || i < end_ids_count - 1) { + if (m->next != NULL || i < count - 1) { fprintf(f, ", "); } } @@ -500,11 +494,12 @@ endleaf_rust(FILE *f, const struct fsm_end_ids *end_ids, } static int -endleaf_dot(FILE *f, const struct fsm_end_ids *end_ids, - const void *endleaf_opaque) +endleaf_dot(FILE *f, + const fsm_end_id_t *ids, size_t count, + const void *endleaf_opaque) { const struct match *m; - size_t i, end_ids_count; + size_t i; assert(f != NULL); assert(endleaf_opaque == NULL); @@ -513,13 +508,11 @@ endleaf_dot(FILE *f, const struct fsm_end_ids *end_ids, fprintf(f, "label = <"); - end_ids_count = (end_ids == NULL ? 0 : end_ids->count); - - for (i = 0; i < end_ids_count; i++) { - for (m = find_match_with_id(end_ids->ids[i]); m != NULL; m = m->next) { - fprintf(f, "#%u", m->i); + for (i = 0; i < count; i++) { + for (m = find_match_with_id(ids[i]); m != NULL; m = m->next) { + fprintf(f, "#%u", m->id); - if (m->next != NULL || i < end_ids_count - 1) { + if (m->next != NULL || i < count - 1) { fprintf(f, ","); } } @@ -533,11 +526,11 @@ endleaf_dot(FILE *f, const struct fsm_end_ids *end_ids, #if 0 fprintf(f, " # "); - for (i = 0; i < end_ids_count; i++) { - for (m = find_match_with_id(end_ids->ids[i]); m != NULL; m = m->next) { + for (i = 0; i < count; i++) { + for (m = find_match_with_id(ids[i]); m != NULL; m = m->next) { fprintf(f, "\"%s\"", m->s); /* XXX: escape string (and comment) */ - if (m->next != NULL || i < end_ids_count - 1) { + if (m->next != NULL || i < count - 1) { fprintf(f, ", "); } } @@ -550,11 +543,12 @@ endleaf_dot(FILE *f, const struct fsm_end_ids *end_ids, } static int -endleaf_json(FILE *f, const struct fsm_end_ids *end_ids, - const void *endleaf_opaque) +endleaf_json(FILE *f, + const fsm_end_id_t *ids, size_t count, + const void *endleaf_opaque) { const struct match *m; - size_t i, end_ids_count; + size_t i; assert(f != NULL); assert(endleaf_opaque == NULL); @@ -563,11 +557,9 @@ endleaf_json(FILE *f, const struct fsm_end_ids *end_ids, fprintf(f, "[ "); - end_ids_count = (end_ids == NULL ? 0 : end_ids->count); - - for (i = 0; i < end_ids_count; i++) { - for (m = find_match_with_id(end_ids->ids[i]); m != NULL; m = m->next) { - fprintf(f, "%u", m->i); + for (i = 0; i < count; i++) { + for (m = find_match_with_id(ids[i]); m != NULL; m = m->next) { + fprintf(f, "%u", m->id); if (m->next != NULL) { fprintf(f, ", "); diff --git a/tests/capture/captest.c b/tests/capture/captest.c index dc66f81d4..d1b5c510a 100644 --- a/tests/capture/captest.c +++ b/tests/capture/captest.c @@ -89,19 +89,18 @@ captest_run_single(const struct captest_single_fsm_test_info *info) if (end != strlen(info->string)) { FAIL("exec end pos"); } { - fsm_end_id_t id_buf[1] = { ~0 }; - enum fsm_getendids_res gres; - size_t written; - if (1 != fsm_getendidcount(fsm, end)) { + fsm_end_id_t ids[1] = { ~0 }; + int gres; + if (1 != fsm_endid_count(fsm, end)) { FAIL("did not have exactly one end ID"); } - gres = fsm_getendids(fsm, end, 1, id_buf, &written); - if (gres != FSM_GETENDIDS_FOUND) { + gres = fsm_endid_get(fsm, end, 1, ids); + if (gres != 1) { FAIL("failed to get end IDs"); } - if (0 != id_buf[0]) { + if (0 != ids[0]) { FAIL("failed to get end ID of 0"); } } @@ -181,27 +180,26 @@ int captest_check_single_end_id(const struct fsm *fsm, fsm_state_t end_state, unsigned expected_end_id, const char **msg) { - fsm_end_id_t id_buf[1] = { ~0 }; - enum fsm_getendids_res gres; - size_t written; + fsm_end_id_t ids[1] = { ~0 }; + int gres; const char *unused; if (msg == NULL) { msg = &unused; } - if (1 != fsm_getendidcount(fsm, end_state)) { + if (1 != fsm_endid_count(fsm, end_state)) { *msg = "did not have exactly one end ID"; return 0; } - gres = fsm_getendids(fsm, end_state, 1, id_buf, &written); - if (gres != FSM_GETENDIDS_FOUND) { + gres = fsm_endid_get(fsm, end_state, 1, ids); + if (gres != 1) { *msg = "failed to get end IDs"; return 0; } - if (expected_end_id != id_buf[0]) { + if (expected_end_id != ids[0]) { *msg = "failed to get expected end ID"; return 0; } diff --git a/tests/capture/capture4.c b/tests/capture/capture4.c index 170cbe8b0..313086c97 100644 --- a/tests/capture/capture4.c +++ b/tests/capture/capture4.c @@ -220,21 +220,21 @@ check(const struct fsm *fsm, const char *string, assert(captures[cb_b].pos[1] == pb_1); { - enum fsm_getendids_res gres; - fsm_end_id_t id_buf[2]; - size_t written; - gres = fsm_getendids(fsm, end, 2, id_buf, &written); - if (gres != FSM_GETENDIDS_FOUND) { + int gres; + fsm_end_id_t ids[2]; + + gres = fsm_endid_get(fsm, end, 2, ids); + if (gres != 1) { assert(!"fsm_getendids failed"); } if (expected_ends == 0x2) { - assert(written == 1); - assert(id_buf[0] == 1); + assert(fsm_endid_count(fsm, end) == 1); + assert(ids[0] == 1); } else if (expected_ends == 0x3) { - assert(written == 2); - assert(id_buf[0] == 0); - assert(id_buf[1] == 1); + assert(fsm_endid_count(fsm, end) == 2); + assert(ids[0] == 0); + assert(ids[1] == 1); } else { assert(!"test not handled"); } diff --git a/tests/endids/endids0.c b/tests/endids/endids0.c index f101f0cc6..c9117c0b0 100644 --- a/tests/endids/endids0.c +++ b/tests/endids/endids0.c @@ -43,23 +43,19 @@ int main(void) // memset(all_endids, 0, sizeof all_endids); for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endid = 0; - size_t nwritten; - enum fsm_getendids_res ret; + fsm_end_id_t id = 0; + int ret; - assert( fsm_getendidcount(fsm, state_ind) == 1); + assert( fsm_endid_count(fsm, state_ind) == 1); - nwritten = 0; - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, 1, - &endid, - &nwritten); + &id); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == 1); - assert( endid == 1 ); + assert(ret == 1); + assert(id == 1); nend++; } @@ -88,26 +84,26 @@ int main(void) }; for (i=0; i < sizeof matches / sizeof matches[0]; i++) { - fsm_end_id_t *end_ids; - size_t num_end_ids; + fsm_end_id_t *ids; + size_t count; - end_ids = NULL; - num_end_ids = 0; - ret = match_string(fsm, matches[i].s, NULL, &end_ids, &num_end_ids); + ids = NULL; + count = 0; + ret = match_string(fsm, matches[i].s, NULL, &ids, &count); if (matches[i].should_match) { assert( ret == 1 ); - assert( end_ids != NULL ); - assert( end_ids[0] = 1 ); - assert( num_end_ids == 1 ); - assert( end_ids[0] = matches[i].endid ); + assert( ids != NULL ); + assert( ids[0] = 1 ); + assert( count == 1 ); + assert( ids[0] = matches[i].endid ); } else { assert( ret == 0 ); - assert( end_ids == NULL ); - assert( num_end_ids == 0 ); + assert( ids == NULL ); + assert( count == 0 ); } - free(end_ids); + free(ids); } } diff --git a/tests/endids/endids0_many_endids.c b/tests/endids/endids0_many_endids.c index cd5230855..0af45112b 100644 --- a/tests/endids/endids0_many_endids.c +++ b/tests/endids/endids0_many_endids.c @@ -39,18 +39,18 @@ int main(void) * * 17 endids. This should force the array of end ids to resize. */ - static const fsm_end_id_t all_end_ids[17] = { + static const fsm_end_id_t all_ids[17] = { 4, 17, 6, 18, 2, 63, 14, 62, 3, 37, 46, 7, 9, 72, 67, 36, 1, }; - static const fsm_end_id_t sorted_all_end_ids[17] = { + static const fsm_end_id_t sorted_all_ids[17] = { 1, 2, 3, 4, 6, 7, 9, 14, 17, 18, 36, 37, 46, 62, 63, 67, 72, }; - for (size_t i=0; i < sizeof all_end_ids / sizeof all_end_ids[0]; i++) { - ret = fsm_setendid(fsm, all_end_ids[i]); + for (size_t i=0; i < sizeof all_ids / sizeof all_ids[0]; i++) { + ret = fsm_setendid(fsm, all_ids[i]); assert(ret == 1); } @@ -69,50 +69,49 @@ int main(void) assert(end_state < nstates); - assert(fsm_getendidcount(fsm, end_state) == sizeof all_end_ids / sizeof all_end_ids[0]); - for (i=0; i < sizeof all_end_ids / sizeof all_end_ids[0]; i++) { + assert(fsm_endid_count(fsm, end_state) == sizeof all_ids / sizeof all_ids[0]); + for (i=0; i < sizeof all_ids / sizeof all_ids[0]; i++) { /* add duplicate end ids */ - ret = fsm_setendid(fsm, all_end_ids[i]); + ret = fsm_setendid(fsm, all_ids[i]); /* fsm_setendid should succeed */ assert(ret == 1); /* but it shouldn't add a duplicate id */ - assert(fsm_getendidcount(fsm, end_state) == sizeof all_end_ids / sizeof all_end_ids[0]); + assert(fsm_endid_count(fsm, end_state) == sizeof all_ids / sizeof all_ids[0]); } nend = 0; for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endids[sizeof all_end_ids / sizeof all_end_ids[0]]; - size_t i, nwritten; - enum fsm_getendids_res ret; + fsm_end_id_t endids[sizeof all_ids / sizeof all_ids[0]]; + size_t i; + int ret; memset(&endids[0], 0, sizeof endids); - assert(fsm_getendidcount(fsm, state_ind) == sizeof all_end_ids / sizeof all_end_ids[0]); + assert(fsm_endid_count(fsm, state_ind) == sizeof all_ids / sizeof all_ids[0]); - nwritten = 0; - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, - sizeof endids/sizeof endids[0], - &endids[0], - &nwritten); + sizeof endids / sizeof endids[0], + &endids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == sizeof all_end_ids / sizeof all_end_ids[0]); + assert(ret == 1); - /* sort endids and compare */ - qsort(&endids[0], nwritten, sizeof endids[0], cmp_endids); - for (i=0; i < nwritten; i++) { - assert(endids[i] == sorted_all_end_ids[i]); + /* sort endids and compare */ + qsort(&endids[0], + sizeof endids / sizeof endids[0], sizeof endids[0], + cmp_endids); + for (i=0; i < fsm_endid_count(fsm, state_ind); i++) { + assert(endids[i] == sorted_all_ids[i]); } #if 0 /* endids should be sorted */ for (i=0; i < nwritten; i++) { - assert(endids[i] == sorted_all_end_ids[i]); + assert(endids[i] == sorted_all_ids[i]); } #endif /* 0 */ @@ -142,38 +141,38 @@ int main(void) }; for (i=0; i < sizeof matches / sizeof matches[0]; i++) { - fsm_end_id_t *end_ids; - size_t num_end_ids; + fsm_end_id_t *ids; + size_t count; - end_ids = NULL; - num_end_ids = 0; - ret = match_string(fsm, matches[i].s, NULL, &end_ids, &num_end_ids); + ids = NULL; + count = 0; + ret = match_string(fsm, matches[i].s, NULL, &ids, &count); if (matches[i].should_match) { size_t j; assert( ret == 1 ); - assert( end_ids != NULL ); - assert( num_end_ids == sizeof all_end_ids / sizeof all_end_ids[0] ); + assert( ids != NULL ); + assert( count == sizeof all_ids / sizeof all_ids[0] ); #if 0 - assert( end_ids[0] == 1 ); - assert( end_ids[0] == matches[i].endid ); + assert( ids[0] == 1 ); + assert( ids[0] == matches[i].endid ); #endif /* 0 */ /* sort endids and compare */ - qsort(&end_ids[0], num_end_ids, sizeof end_ids[0], cmp_endids); + qsort(&ids[0], count, sizeof ids[0], cmp_endids); - for (j=0; j < num_end_ids; j++) { - assert(end_ids[j] == sorted_all_end_ids[j]); + for (j=0; j < count; j++) { + assert(ids[j] == sorted_all_ids[j]); } } else { assert( ret == 0 ); - assert( end_ids == NULL ); - assert( num_end_ids == 0 ); + assert( ids == NULL ); + assert( count == 0 ); } - free(end_ids); + free(ids); } } diff --git a/tests/endids/endids1_determinise.c b/tests/endids/endids1_determinise.c index 956e0ee33..3860aefca 100644 --- a/tests/endids/endids1_determinise.c +++ b/tests/endids/endids1_determinise.c @@ -40,22 +40,18 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { fsm_end_id_t endid = 0; - size_t nwritten; - enum fsm_getendids_res ret; + int ret; - assert( fsm_getendidcount(fsm, state_ind) == 1); + assert( fsm_endid_count(fsm, state_ind) == 1); - nwritten = 0; - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, 1, - &endid, - &nwritten); + &endid); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == 1); - assert( endid == 1 ); + assert(ret == 1); + assert( endid == 1 ); } } @@ -79,26 +75,26 @@ int main(void) }; for (i=0; i < sizeof matches / sizeof matches[0]; i++) { - fsm_end_id_t *end_ids; - size_t num_end_ids; + fsm_end_id_t *ids; + size_t count; - end_ids = NULL; - num_end_ids = 0; - ret = match_string(fsm, matches[i].s, NULL, &end_ids, &num_end_ids); + ids = NULL; + count = 0; + ret = match_string(fsm, matches[i].s, NULL, &ids, &count); if (matches[i].should_match) { assert( ret == 1 ); - assert( end_ids != NULL ); - assert( end_ids[0] = 1 ); - assert( num_end_ids == 1 ); - assert( end_ids[0] = matches[i].endid ); + assert( ids != NULL ); + assert( ids[0] = 1 ); + assert( count == 1 ); + assert( ids[0] = matches[i].endid ); } else { assert( ret == 0 ); - assert( end_ids == NULL ); - assert( num_end_ids == 0 ); + assert( ids == NULL ); + assert( count == 0 ); } - free(end_ids); + free(ids); } } diff --git a/tests/endids/endids1_determinise_and_minimise.c b/tests/endids/endids1_determinise_and_minimise.c index 4619af4a8..bb0711905 100644 --- a/tests/endids/endids1_determinise_and_minimise.c +++ b/tests/endids/endids1_determinise_and_minimise.c @@ -45,22 +45,18 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { fsm_end_id_t endid = 0; - size_t nwritten; - enum fsm_getendids_res ret; + int ret; - assert( fsm_getendidcount(fsm, state_ind) == 1); + assert(fsm_endid_count(fsm, state_ind) == 1); - nwritten = 0; - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, 1, - &endid, - &nwritten); + &endid); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == 1); - assert( endid == 1 ); + assert(ret == 1); + assert( endid == 1 ); } } @@ -84,26 +80,26 @@ int main(void) }; for (i=0; i < sizeof matches / sizeof matches[0]; i++) { - fsm_end_id_t *end_ids; - size_t num_end_ids; + fsm_end_id_t *ids; + size_t count; - end_ids = NULL; - num_end_ids = 0; - ret = match_string(fsm, matches[i].s, NULL, &end_ids, &num_end_ids); + ids = NULL; + count = 0; + ret = match_string(fsm, matches[i].s, NULL, &ids, &count); if (matches[i].should_match) { assert( ret == 1 ); - assert( end_ids != NULL ); - assert( end_ids[0] = 1 ); - assert( num_end_ids == 1 ); - assert( end_ids[0] = matches[i].endid ); + assert( ids != NULL ); + assert( ids[0] = 1 ); + assert( count == 1 ); + assert( ids[0] = matches[i].endid ); } else { assert( ret == 0 ); - assert( end_ids == NULL ); - assert( num_end_ids == 0 ); + assert( ids == NULL ); + assert( count == 0 ); } - free(end_ids); + free(ids); } } diff --git a/tests/endids/endids2_union.c b/tests/endids/endids2_union.c index d65ef17e8..c990e7c95 100644 --- a/tests/endids/endids2_union.c +++ b/tests/endids/endids2_union.c @@ -55,32 +55,28 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(comb, state_ind)) { fsm_end_id_t endids[2] = {0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(comb, state_ind); - // fprintf(stderr, "state %u, num_endids = %zu\n", state_ind, num_endids); + count = fsm_endid_count(comb, state_ind); + // fprintf(stderr, "state %u, count = %zu\n", state_ind, count); - assert( num_endids > 0 && num_endids <= 2); + assert( count > 0 && count <= 2); - ret = fsm_getendids( + ret = fsm_endid_get( comb, state_ind, 2, - &endids[0], - &nwritten); + &endids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); - if (nwritten == 1) { + if (count == 1) { assert(endids[0] == 1 || endids[0] == 2); has_endid_1 = has_endid_1 || (endids[0] == 1); has_endid_2 = has_endid_2 || (endids[0] == 2); - } else if (nwritten == 2) { + } else if (count == 2) { assert((endids[0] == 1 && endids[1] == 2) || (endids[0] == 2 && endids[1] == 1)); @@ -111,7 +107,7 @@ int main(void) static const struct { const char *s; int should_match; - size_t num_endids; + size_t count; fsm_end_id_t endid[2]; } matches[] = { { "abc" , 1, 1, { 1, 0 } }, @@ -147,33 +143,33 @@ int main(void) }; for (i=0; i < sizeof matches / sizeof matches[0]; i++) { - fsm_end_id_t *end_ids; - size_t num_end_ids; + fsm_end_id_t *ids; + size_t count; - end_ids = NULL; - num_end_ids = 0; - ret = match_string(comb, matches[i].s, NULL, &end_ids, &num_end_ids); + ids = NULL; + count = 0; + ret = match_string(comb, matches[i].s, NULL, &ids, &count); if (matches[i].should_match) { size_t j; assert( ret == 1 ); - assert( end_ids != NULL ); + assert( ids != NULL ); - assert( num_end_ids == matches[i].num_endids ); + assert( count == matches[i].count ); - qsort(&end_ids[0], num_end_ids, sizeof end_ids[0], cmp_endids); + qsort(&ids[0], count, sizeof ids[0], cmp_endids); - for (j=0; j < num_end_ids; j++) { - assert( end_ids[j] == matches[i].endid[j] ); + for (j=0; j < count; j++) { + assert( ids[j] == matches[i].endid[j] ); } } else { assert( ret == 0 ); - assert( end_ids == NULL ); - assert( num_end_ids == 0 ); + assert( ids == NULL ); + assert( count == 0 ); } - free(end_ids); + free(ids); } } diff --git a/tests/endids/endids2_union_many_endids.c b/tests/endids/endids2_union_many_endids.c index 46f2a189e..deafcff1e 100644 --- a/tests/endids/endids2_union_many_endids.c +++ b/tests/endids/endids2_union_many_endids.c @@ -121,18 +121,18 @@ size_t generate_examples(struct example_list *l, const struct fsm *fsm, size_t p return (first_index != SIZE_MAX) ? first_index : 0; } -/* test that endids correctly propagate through union, determinise, and minimise */ +/* test that ids correctly propagate through union, determinise, and minimise */ int main(void) { struct fsm *fsm; - fsm_end_id_t all_endids[NUM_PATTERNS]; + fsm_end_id_t all_ids[NUM_PATTERNS]; size_t nstates, state_ind; size_t i; int ret; struct example_list example_list; - memset(all_endids, 0, sizeof all_endids); + memset(all_ids, 0, sizeof all_ids); init_examples(&example_list); @@ -176,39 +176,36 @@ int main(void) ret = fsm_determinise(fsm); assert(ret != 0); - // find end states, make sure we have multiple end states and they each have endids + // find end states, make sure we have multiple end states and they each have ids nstates = fsm_countstates(fsm); for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { int tested_pattern[NUM_PATTERNS]; - fsm_end_id_t endids[NUM_ENDIDS_TOTAL]; - size_t nwritten, num_endids, j; - enum fsm_getendids_res ret; + fsm_end_id_t ids[NUM_ENDIDS_TOTAL]; + size_t count, j; + int ret; - memset(&endids[0], 0, sizeof endids); + memset(&ids[0], 0, sizeof ids); - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert(num_endids > 0 && num_endids <= sizeof endids/sizeof endids[0]); + assert(count > 0 && count <= sizeof ids/sizeof ids[0]); - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, - sizeof endids/sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids/sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); memset(&tested_pattern[0], 0, sizeof tested_pattern); - for (j=0; j < num_endids; j++) { + for (j=0; j < count; j++) { size_t k, pattern_index; - pattern_index = (endids[j] - 1)/NUM_ENDIDS_PER_PATTERN; + pattern_index = (ids[j] - 1)/NUM_ENDIDS_PER_PATTERN; assert(pattern_index < NUM_PATTERNS); if (tested_pattern[pattern_index]) { @@ -227,11 +224,11 @@ int main(void) if (ret) { #if 0 printf("end state %zu (end id %u) matches example \"%s\" from pattern /%s/\n", - state_ind, endids[j], ex->example, patterns[pattern_index]); + state_ind, ids[j], ex->example, patterns[pattern_index]); #endif /* 0 */ } else { printf("end state %zu (end id %u) does NOT match example \"%s\" from pattern /%s/\n", - state_ind, endids[j], ex->example, patterns[pattern_index]); + state_ind, ids[j], ex->example, patterns[pattern_index]); abort(); } } @@ -243,32 +240,29 @@ int main(void) assert(ret != 0); /* fsm_minimise should not collapse all the end states to a - * single end state, because they have distinct endids. */ + * single end state, because they have distinct ids. */ assert( fsm_count(fsm, fsm_isend) > 1); nstates = fsm_countstates(fsm); for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endids[NUM_ENDIDS_TOTAL]; - size_t nwritten, num_endids; - enum fsm_getendids_res ret; + fsm_end_id_t ids[NUM_ENDIDS_TOTAL]; + size_t count; + int ret; - memset(&endids[0], 0, sizeof endids); + memset(&ids[0], 0, sizeof ids); - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert(num_endids <= NUM_ENDIDS_TOTAL); + assert(count <= NUM_ENDIDS_TOTAL); - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, - sizeof endids/sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids/sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); } } diff --git a/tests/endids/endids4.c b/tests/endids/endids4.c index c8f312663..80afbcc39 100644 --- a/tests/endids/endids4.c +++ b/tests/endids/endids4.c @@ -67,29 +67,25 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(comb, state_ind)) { fsm_end_id_t endids[2] = {0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(comb, state_ind); + count = fsm_endid_count(comb, state_ind); - printf("state %u num_endids = %zu\n", state_ind, num_endids); + printf("state %u count = %zu\n", state_ind, count); - assert(num_endids == 2); + assert(count == 2); - ret = fsm_getendids( + ret = fsm_endid_get( comb, state_ind, 2, - &endids[0], - &nwritten); + &endids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); - qsort(&endids[0], num_endids, sizeof endids[0], cmp_endids); - assert(endids[0] == 1 && endids[1] == 2); + qsort(&endids[0], count, sizeof endids[0], cmp_endids); + assert(endids[0] == 1 && endids[1] == 2); } } @@ -102,7 +98,7 @@ int main(void) static const struct { const char *s; int should_match; - size_t num_endids; + size_t count; fsm_end_id_t endid[2]; } matches[] = { { "abc" , 0, 0, { 0, 0 } }, @@ -138,33 +134,33 @@ int main(void) }; for (i=0; i < sizeof matches / sizeof matches[0]; i++) { - fsm_end_id_t *end_ids; - size_t num_end_ids; + fsm_end_id_t *ids; + size_t count; - end_ids = NULL; - num_end_ids = 0; - ret = match_string(comb, matches[i].s, NULL, &end_ids, &num_end_ids); + ids = NULL; + count = 0; + ret = match_string(comb, matches[i].s, NULL, &ids, &count); if (matches[i].should_match) { size_t j; assert( ret == 1 ); - assert( end_ids != NULL ); + assert( ids != NULL ); - assert( num_end_ids == matches[i].num_endids ); + assert( count == matches[i].count ); - qsort(&end_ids[0], num_end_ids, sizeof end_ids[0], cmp_endids); + qsort(&ids[0], count, sizeof ids[0], cmp_endids); - for (j=0; j < num_end_ids; j++) { - assert( end_ids[j] == matches[i].endid[j] ); + for (j=0; j < count; j++) { + assert( ids[j] == matches[i].endid[j] ); } } else { assert( ret == 0 ); - assert( end_ids == NULL ); - assert( num_end_ids == 0 ); + assert( ids == NULL ); + assert( count == 0 ); } - free(end_ids); + free(ids); } } diff --git a/tests/endids/endids5.c b/tests/endids/endids5.c index f6220115a..d6a713843 100644 --- a/tests/endids/endids5.c +++ b/tests/endids/endids5.c @@ -68,28 +68,24 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(comb, state_ind)) { fsm_end_id_t endids[2] = {0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(comb, state_ind); + count = fsm_endid_count(comb, state_ind); - printf("state %u num_endids = %zu\n", state_ind, num_endids); + printf("state %u count = %zu\n", state_ind, count); - assert(num_endids == 1); + assert(count == 1); - ret = fsm_getendids( + ret = fsm_endid_get( comb, state_ind, 2, - &endids[0], - &nwritten); + &endids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); - assert(endids[0] == 1); + assert(endids[0] == 1); } } @@ -102,7 +98,7 @@ int main(void) static const struct { const char *s; int should_match; - size_t num_endids; + size_t count; fsm_end_id_t endid[2]; } matches[] = { { "abc" , 1, 1, { 1, 0 } }, @@ -138,37 +134,37 @@ int main(void) }; for (i=0; i < sizeof matches / sizeof matches[0]; i++) { - fsm_end_id_t *end_ids; - size_t num_end_ids; + fsm_end_id_t *ids; + size_t count; - end_ids = NULL; - num_end_ids = 0; - ret = match_string(comb, matches[i].s, NULL, &end_ids, &num_end_ids); + ids = NULL; + count = 0; + ret = match_string(comb, matches[i].s, NULL, &ids, &count); - printf("match %zu, \"%s\", should_match=%d, num_endids=%zu, endids={ %u, %u }\n", - i, matches[i].s, matches[i].should_match, matches[i].num_endids, + printf("match %zu, \"%s\", should_match=%d, count=%zu, endids={ %u, %u }\n", + i, matches[i].s, matches[i].should_match, matches[i].count, (unsigned)matches[i].endid[0], (unsigned)matches[i].endid[1]); if (matches[i].should_match) { size_t j; assert( ret == 1 ); - assert( end_ids != NULL ); + assert( ids != NULL ); - assert( num_end_ids == matches[i].num_endids ); + assert( count == matches[i].count ); - qsort(&end_ids[0], num_end_ids, sizeof end_ids[0], cmp_endids); + qsort(&ids[0], count, sizeof ids[0], cmp_endids); - for (j=0; j < num_end_ids; j++) { - assert( end_ids[j] == matches[i].endid[j] ); + for (j=0; j < count; j++) { + assert( ids[j] == matches[i].endid[j] ); } } else { assert( ret == 0 ); - assert( end_ids == NULL ); - assert( num_end_ids == 0 ); + assert( ids == NULL ); + assert( count == 0 ); } - free(end_ids); + free(ids); } } diff --git a/tests/endids/endids6.c b/tests/endids/endids6.c index ca089d0f1..34b261118 100644 --- a/tests/endids/endids6.c +++ b/tests/endids/endids6.c @@ -19,34 +19,34 @@ struct state_info { fsm_state_t state; - unsigned num_endids; - fsm_end_id_t endids[2]; + unsigned count; + fsm_end_id_t ids[2]; }; /* remap 1 -> 512, 2 -> 1024 */ static int -endid_remap_func(fsm_state_t state, size_t num_ids, fsm_end_id_t *endids, size_t *num_written, void *opaque) +endid_remap_func(fsm_state_t state, size_t count, fsm_end_id_t *ids, size_t *num_written, void *opaque) { size_t i; (void)state; (void)opaque; - assert(endids != NULL); - for (i=0; i < num_ids; i++) { - fsm_end_id_t orig = endids[i]; + assert(ids != NULL); + for (i=0; i < count; i++) { + fsm_end_id_t orig = ids[i]; - switch (endids[i]) { - case 1: endids[i] = 512; break; - case 2: endids[i] = 1024; break; + switch (ids[i]) { + case 1: ids[i] = 512; break; + case 2: ids[i] = 1024; break; default: break; } printf("remap: state %u id %u -> %u\n", - (unsigned)state, (unsigned)orig, (unsigned)endids[i]); + (unsigned)state, (unsigned)orig, (unsigned)ids[i]); } - *num_written = num_ids; + *num_written = count; return 1; } @@ -91,37 +91,33 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endids[2] = {0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + fsm_end_id_t ids[2] = {0,0}; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert( num_endids > 0 && num_endids <= 2); + assert( count > 0 && count <= 2); - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, - sizeof endids / sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids / sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); info[ninfo].state = state_ind; - info[ninfo].num_endids = nwritten; - - if (nwritten == 1) { - assert(endids[0] == 1 || endids[0] == 2); - info[ninfo].endids[0] = endids[0]; - } else if (nwritten == 2) { - qsort(&endids[0], nwritten, sizeof endids[0], cmp_endids); - assert(endids[0] == 1 && endids[1] == 2); - info[ninfo].endids[0] = endids[0]; - info[ninfo].endids[1] = endids[1]; + info[ninfo].count = count; + + if (count == 1) { + assert(ids[0] == 1 || ids[0] == 2); + info[ninfo].ids[0] = ids[0]; + } else if (count == 2) { + qsort(&ids[0], count, sizeof ids[0], cmp_endids); + assert(ids[0] == 1 && ids[1] == 2); + info[ninfo].ids[0] = ids[0]; + info[ninfo].ids[1] = ids[1]; } ninfo++; @@ -136,35 +132,32 @@ int main(void) for (state_ind = 0, info_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endids[2] = {0,0}; - size_t nwritten, num_endids, ind; - enum fsm_getendids_res ret; + fsm_end_id_t ids[2] = {0,0}; + size_t count, ind; + int ret; assert( state_ind == info[info_ind].state ); - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert(num_endids > 0 && num_endids <= 2); + assert(count > 0 && count <= 2); - assert( num_endids == info[info_ind].num_endids ); - ret = fsm_getendids( + assert( count == info[info_ind].count ); + ret = fsm_endid_get( fsm, state_ind, - sizeof endids / sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids / sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); - if (nwritten > 1) { - qsort(&endids[0], num_endids, sizeof endids[0], cmp_endids); + if (count > 1) { + qsort(&ids[0], count, sizeof ids[0], cmp_endids); } - for (ind=0; ind < num_endids; ind++) { - fsm_end_id_t expected = info[info_ind].endids[ind]; - switch (info[info_ind].endids[ind]) { + for (ind=0; ind < count; ind++) { + fsm_end_id_t expected = info[info_ind].ids[ind]; + switch (info[info_ind].ids[ind]) { case 1: expected = 512; break; case 2: expected = 1024; break; default: @@ -172,8 +165,8 @@ int main(void) break; } - printf("state %u, id %u, expected %u\n", (unsigned)state_ind, endids[ind], expected); - assert(endids[ind] == expected); + printf("state %u, id %u, expected %u\n", (unsigned)state_ind, ids[ind], expected); + assert(ids[ind] == expected); } info_ind++; diff --git a/tests/endids/endids7.c b/tests/endids/endids7.c index cc68d02c0..6508308eb 100644 --- a/tests/endids/endids7.c +++ b/tests/endids/endids7.c @@ -19,41 +19,41 @@ struct state_info { fsm_state_t state; - unsigned num_endids; - fsm_end_id_t endids[2]; + unsigned count; + fsm_end_id_t ids[2]; }; /* remap 1 -> 7, 2 -> 9, both 1&2 -> 3 */ static int -endid_remap_func(fsm_state_t state, size_t num_ids, fsm_end_id_t *endids, size_t *num_written, void *opaque) +endid_remap_func(fsm_state_t state, size_t num_ids, fsm_end_id_t *ids, size_t *num_written, void *opaque) { (void)state; (void)opaque; - assert(endids != NULL); + assert(ids != NULL); assert(num_ids > 0 && num_ids <= 2); if (num_ids > 1) { - endids[0] = 3; + ids[0] = 3; *num_written = 1; printf("remap: state %u with %zu endids, set to one endid, value %u\n", - (unsigned)state, num_ids, (unsigned)endids[0]); + (unsigned)state, num_ids, (unsigned)ids[0]); return 1; } if (num_ids == 1) { - fsm_end_id_t orig = endids[0]; + fsm_end_id_t orig = ids[0]; - switch (endids[0]) { - case 1: endids[0] = 7; break; - case 2: endids[0] = 9; break; + switch (ids[0]) { + case 1: ids[0] = 7; break; + case 2: ids[0] = 9; break; default: break; } printf("remap: state %u id %u -> %u\n", - (unsigned)state, (unsigned)orig, (unsigned)endids[0]); + (unsigned)state, (unsigned)orig, (unsigned)ids[0]); } *num_written = num_ids; @@ -103,37 +103,33 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endids[2] = {0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + fsm_end_id_t ids[2] = {0,0}; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert( num_endids > 0 && num_endids <= 2); + assert( count > 0 && count <= 2); - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, - sizeof endids / sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids / sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); info[ninfo].state = state_ind; - info[ninfo].num_endids = nwritten; - - if (nwritten == 1) { - assert(endids[0] == 1 || endids[0] == 2); - info[ninfo].endids[0] = endids[0]; - } else if (nwritten == 2) { - qsort(&endids[0], nwritten, sizeof endids[0], cmp_endids); - assert(endids[0] == 1 && endids[1] == 2); - info[ninfo].endids[0] = endids[0]; - info[ninfo].endids[1] = endids[1]; + info[ninfo].count = count; + + if (count == 1) { + assert(ids[0] == 1 || ids[0] == 2); + info[ninfo].ids[0] = ids[0]; + } else if (count == 2) { + qsort(&ids[0], count, sizeof ids[0], cmp_endids); + assert(ids[0] == 1 && ids[1] == 2); + info[ninfo].ids[0] = ids[0]; + info[ninfo].ids[1] = ids[1]; } ninfo++; @@ -148,39 +144,36 @@ int main(void) for (state_ind = 0, info_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endid = 0; + fsm_end_id_t id = 0; fsm_end_id_t expected; - size_t nwritten, num_endids; - enum fsm_getendids_res ret; + size_t count; + int ret; assert( state_ind == info[info_ind].state ); - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert(num_endids == 1); - ret = fsm_getendids( + assert(count == 1); + ret = fsm_endid_get( fsm, state_ind, 1, - &endid, - &nwritten); + &id); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); - if (info[info_ind].num_endids == 2) { + if (info[info_ind].count == 2) { expected = 3; - } else if (info[info_ind].endids[0] == 1) { + } else if (info[info_ind].ids[0] == 1) { expected = 7; - } else if (info[info_ind].endids[0] == 2) { + } else if (info[info_ind].ids[0] == 2) { expected = 9; } else { assert( ! "unexpected value" ); } - printf("state %u, id %u, expected %u\n", (unsigned)state_ind, endid, expected); - assert(endid == expected);; + printf("state %u, id %u, expected %u\n", (unsigned)state_ind, id, expected); + assert(id == expected);; info_ind++; } diff --git a/tests/endids/endids7_with_duplicates.c b/tests/endids/endids7_with_duplicates.c index b554f7cb6..6b01d5f15 100644 --- a/tests/endids/endids7_with_duplicates.c +++ b/tests/endids/endids7_with_duplicates.c @@ -19,45 +19,45 @@ struct state_info { fsm_state_t state; - unsigned num_endids; - fsm_end_id_t endids[2]; + unsigned count; + fsm_end_id_t ids[2]; }; /* remap 1 -> 7, 2 -> 9, both 1&2 -> 3,3 */ static int -endid_remap_func(fsm_state_t state, size_t num_ids, fsm_end_id_t *endids, size_t *num_written, void *opaque) +endid_remap_func(fsm_state_t state, size_t num_ids, fsm_end_id_t *ids, size_t *num_written, void *opaque) { (void)state; (void)opaque; - assert(endids != NULL); + assert(ids != NULL); assert(num_ids > 0 && num_ids <= 2); if (num_ids > 1) { size_t i; for (i = 0; i < num_ids; i++) { - endids[i] = 3; + ids[i] = 3; } *num_written = num_ids; printf("remap: state %u with %zu endids, set to %zu endid, value %u\n", - (unsigned)state, num_ids, *num_written, (unsigned)endids[0]); + (unsigned)state, num_ids, *num_written, (unsigned) ids[0]); return 1; } if (num_ids == 1) { - fsm_end_id_t orig = endids[0]; + fsm_end_id_t orig = ids[0]; - switch (endids[0]) { - case 1: endids[0] = 7; break; - case 2: endids[0] = 9; break; + switch (ids[0]) { + case 1: ids[0] = 7; break; + case 2: ids[0] = 9; break; default: break; } printf("remap: state %u id %u -> %u\n", - (unsigned)state, (unsigned)orig, (unsigned)endids[0]); + (unsigned)state, (unsigned)orig, (unsigned) ids[0]); } *num_written = num_ids; @@ -107,37 +107,33 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endids[2] = {0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + fsm_end_id_t ids[2] = {0,0}; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert( num_endids > 0 && num_endids <= 2); + assert( count > 0 && count <= 2); - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, - sizeof endids / sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids / sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); info[ninfo].state = state_ind; - info[ninfo].num_endids = nwritten; - - if (nwritten == 1) { - assert(endids[0] == 1 || endids[0] == 2); - info[ninfo].endids[0] = endids[0]; - } else if (nwritten == 2) { - qsort(&endids[0], nwritten, sizeof endids[0], cmp_endids); - assert(endids[0] == 1 && endids[1] == 2); - info[ninfo].endids[0] = endids[0]; - info[ninfo].endids[1] = endids[1]; + info[ninfo].count = count; + + if (count == 1) { + assert(ids[0] == 1 || ids[0] == 2); + info[ninfo].ids[0] = ids[0]; + } else if (count == 2) { + qsort(&ids[0], count, sizeof ids[0], cmp_endids); + assert(ids[0] == 1 && ids[1] == 2); + info[ninfo].ids[0] = ids[0]; + info[ninfo].ids[1] = ids[1]; } ninfo++; @@ -154,30 +150,27 @@ int main(void) if (fsm_isend(fsm, state_ind)) { fsm_end_id_t endid = 0; fsm_end_id_t expected; - size_t nwritten, num_endids; - enum fsm_getendids_res ret; + size_t count; + int ret; assert( state_ind == info[info_ind].state ); - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert(num_endids == 1); - ret = fsm_getendids( + assert(count == 1); + ret = fsm_endid_get( fsm, state_ind, 1, - &endid, - &nwritten); + &endid); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); - if (info[info_ind].num_endids == 2) { + if (info[info_ind].count == 2) { expected = 3; - } else if (info[info_ind].endids[0] == 1) { + } else if (info[info_ind].ids[0] == 1) { expected = 7; - } else if (info[info_ind].endids[0] == 2) { + } else if (info[info_ind].ids[0] == 2) { expected = 9; } else { assert( ! "unexpected value" ); diff --git a/tests/endids/endids8.c b/tests/endids/endids8.c index e413e71e7..86a2b28c8 100644 --- a/tests/endids/endids8.c +++ b/tests/endids/endids8.c @@ -24,7 +24,7 @@ int main(void) const char *s1, *s2; int ret; - fsm_end_id_t all_endids[2]; + fsm_end_id_t all_ids[2]; unsigned nstates, state_ind; s1 = "abc"; fsm1 = re_comp(RE_NATIVE, fsm_sgetc, &s1, NULL, 0, NULL); @@ -69,33 +69,29 @@ int main(void) nstates = fsm_countstates(comb); // all end states should have BOTH endids - memset(all_endids, 0, sizeof all_endids); + memset(all_ids, 0, sizeof all_ids); for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(comb, state_ind)) { - fsm_end_id_t endids[3] = {0,0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + fsm_end_id_t ids[3] = {0,0,0}; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(comb, state_ind); + count = fsm_endid_count(comb, state_ind); - printf("state %u num_endids = %zu\n", state_ind, num_endids); + printf("state %u count = %zu\n", state_ind, count); - assert(num_endids == 3); + assert(count == 3); - ret = fsm_getendids( + ret = fsm_endid_get( comb, state_ind, - sizeof endids / sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids / sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); - qsort(&endids[0], num_endids, sizeof endids[0], cmp_endids); - assert(endids[0] == 1 && endids[1] == 2 && endids[2] == 4); + qsort(&ids[0], count, sizeof ids[0], cmp_endids); + assert(ids[0] == 1 && ids[1] == 2 && ids[2] == 4); } } diff --git a/tests/endids/endids9.c b/tests/endids/endids9.c index de3f28644..33a872155 100644 --- a/tests/endids/endids9.c +++ b/tests/endids/endids9.c @@ -19,8 +19,8 @@ struct state_info { fsm_state_t state; - unsigned num_endids; - fsm_end_id_t endids[2]; + unsigned count; + fsm_end_id_t ids[2]; }; /* use fsm_increndids to change the endids before a union/intersection */ @@ -71,37 +71,33 @@ int main(void) for (state_ind = 0; state_ind < nstates; state_ind++) { if (fsm_isend(fsm, state_ind)) { - fsm_end_id_t endids[2] = {0,0}; - size_t nwritten; - size_t num_endids; - enum fsm_getendids_res ret; + fsm_end_id_t ids[2] = {0,0}; + size_t count; + int ret; - nwritten = 0; - num_endids = fsm_getendidcount(fsm, state_ind); + count = fsm_endid_count(fsm, state_ind); - assert( num_endids > 0 && num_endids <= 2); + assert( count > 0 && count <= 2); - ret = fsm_getendids( + ret = fsm_endid_get( fsm, state_ind, - sizeof endids / sizeof endids[0], - &endids[0], - &nwritten); + sizeof ids / sizeof ids[0], + &ids[0]); - assert(ret == FSM_GETENDIDS_FOUND); - assert(nwritten == num_endids); + assert(ret == 1); info[ninfo].state = state_ind; - info[ninfo].num_endids = nwritten; - - if (nwritten == 1) { - assert(endids[0] == 11 || endids[0] == 12); - info[ninfo].endids[0] = endids[0]; - } else if (nwritten == 2) { - qsort(&endids[0], nwritten, sizeof endids[0], cmp_endids); - assert(endids[0] == 11 && endids[1] == 12); - info[ninfo].endids[0] = endids[0]; - info[ninfo].endids[1] = endids[1]; + info[ninfo].count = count; + + if (count == 1) { + assert(ids[0] == 11 || ids[0] == 12); + info[ninfo].ids[0] = ids[0]; + } else if (count == 2) { + qsort(&ids[0], count, sizeof ids[0], cmp_endids); + assert(ids[0] == 11 && ids[1] == 12); + info[ninfo].ids[0] = ids[0]; + info[ninfo].ids[1] = ids[1]; } ninfo++; diff --git a/tests/endids/utils.c b/tests/endids/utils.c index 79777e825..882df92c4 100644 --- a/tests/endids/utils.c +++ b/tests/endids/utils.c @@ -4,43 +4,42 @@ #include int -match_string(const struct fsm *fsm, const char *s, fsm_state_t *end_ptr, fsm_end_id_t **endids_ptr, size_t *num_endids_ptr) +match_string(const struct fsm *fsm, const char *s, fsm_state_t *end_ptr, fsm_end_id_t **ids_ptr, size_t *count_ptr) { fsm_state_t end = 0; int ret; ret = fsm_exec(fsm, fsm_sgetc, &s, &end, NULL); if (ret == 1) { - size_t num_endids; + size_t count; if (end_ptr != NULL) { *end_ptr = end; } - num_endids = fsm_getendidcount(fsm, end); - if (num_endids > 0) { - enum fsm_getendids_res ret; - size_t nwritten = 0; + count = fsm_endid_count(fsm, end); + if (count > 0) { + int ret; - fsm_end_id_t *endids = calloc(num_endids, sizeof *endids); - if (endids == NULL) { + fsm_end_id_t *ids = calloc(count, sizeof *ids); + if (ids == NULL) { return -1; } - ret = fsm_getendids(fsm, end, num_endids, endids, &nwritten); - if (ret != FSM_GETENDIDS_FOUND) { - free(endids); - errno = (ret == FSM_GETENDIDS_NOT_FOUND) ? EINVAL : ENOMEM; + ret = fsm_endid_get(fsm, end, count, ids); + if (ret == 0) { + free(ids); + errno = EINVAL; return -1; } - if (endids_ptr != NULL) { - *endids_ptr = endids; - if (num_endids_ptr != NULL) { - *num_endids_ptr = num_endids; + if (ids_ptr != NULL) { + *ids_ptr = ids; + if (count_ptr != NULL) { + *count_ptr = count; } } else { - free(endids); + free(ids); } } } diff --git a/tests/fsm/Makefile b/tests/fsm/Makefile new file mode 100755 index 000000000..6ac0a2646 --- /dev/null +++ b/tests/fsm/Makefile @@ -0,0 +1,22 @@ +.include "../../share/mk/top.mk" + +TEST.tests/fsm != ls -1 tests/fsm/out*.fsm +TEST_SRCDIR.tests/fsm = tests/fsm +TEST_OUTDIR.tests/fsm = ${BUILD}/tests/fsm + +FSM=${BUILD}/bin/fsm + +.for n in ${TEST.tests/fsm:T:R:C/^out//} + +${TEST_OUTDIR.tests/fsm}/got${n}.fsm: ${TEST_SRCDIR.tests/fsm}/in${n}.fsm + ${FSM} -p ${.ALLSRC:M*.fsm} \ + > $@ + +${TEST_OUTDIR.tests/fsm}/res${n}: \ + ${TEST_SRCDIR.tests/fsm}/out${n}.fsm \ + ${TEST_OUTDIR.tests/fsm}/got${n}.fsm + +FSMTEST_RESULT += ${TEST_OUTDIR.tests/fsm}/res${n} + +.endfor + diff --git a/tests/fsm/in0.fsm b/tests/fsm/in0.fsm new file mode 100644 index 000000000..e69de29bb diff --git a/tests/fsm/in1.fsm b/tests/fsm/in1.fsm new file mode 100644 index 000000000..88d443fec --- /dev/null +++ b/tests/fsm/in1.fsm @@ -0,0 +1 @@ +# just a comment diff --git a/tests/fsm/in10.fsm b/tests/fsm/in10.fsm new file mode 100644 index 000000000..8b044d3bb --- /dev/null +++ b/tests/fsm/in10.fsm @@ -0,0 +1,10 @@ +# +# Copyright 2008-2017 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# missing seperator +start: a +end: b + diff --git a/tests/fsm/in11.fsm b/tests/fsm/in11.fsm new file mode 100644 index 000000000..bc058b5e2 --- /dev/null +++ b/tests/fsm/in11.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# missing comma +end: 1 2 3; + diff --git a/tests/fsm/in12.fsm b/tests/fsm/in12.fsm new file mode 100644 index 000000000..973f98c86 --- /dev/null +++ b/tests/fsm/in12.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; +start: b; + diff --git a/tests/fsm/in13.fsm b/tests/fsm/in13.fsm new file mode 100644 index 000000000..0ce5b760a --- /dev/null +++ b/tests/fsm/in13.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2017 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +end: a; +end: a; + diff --git a/tests/fsm/in14.fsm b/tests/fsm/in14.fsm new file mode 100644 index 000000000..82bd7b25c --- /dev/null +++ b/tests/fsm/in14.fsm @@ -0,0 +1,12 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# missing semicolon +0 1; + +start: 0; +end: 1; + diff --git a/tests/fsm/in15.fsm b/tests/fsm/in15.fsm new file mode 100644 index 000000000..f0622bf0f --- /dev/null +++ b/tests/fsm/in15.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; + +# missing ] +end: a = [ ; + diff --git a/tests/fsm/in16.fsm b/tests/fsm/in16.fsm new file mode 100644 index 000000000..0e7fcec60 --- /dev/null +++ b/tests/fsm/in16.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; + +# an empty list is okay +end: a = [ ]; + diff --git a/tests/fsm/in17.fsm b/tests/fsm/in17.fsm new file mode 100644 index 000000000..42df382d5 --- /dev/null +++ b/tests/fsm/in17.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; + +# end-id must be numeric +end: a = [ abc ]; + diff --git a/tests/fsm/in18.fsm b/tests/fsm/in18.fsm new file mode 100644 index 000000000..2cccfc2e5 --- /dev/null +++ b/tests/fsm/in18.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; + +# missing end-id +end: a = [ , ]; + diff --git a/tests/fsm/in19.fsm b/tests/fsm/in19.fsm new file mode 100644 index 000000000..f0875ad1f --- /dev/null +++ b/tests/fsm/in19.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; + +# out of order is okay +end: a = [ 999 ]; + diff --git a/tests/fsm/in2.fsm b/tests/fsm/in2.fsm new file mode 100644 index 000000000..345ab6cc7 --- /dev/null +++ b/tests/fsm/in2.fsm @@ -0,0 +1,13 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# states are named by identifiers +abc; +0; +_x; +_; +abc123; + diff --git a/tests/fsm/in20.fsm b/tests/fsm/in20.fsm new file mode 100644 index 000000000..d025dc47e --- /dev/null +++ b/tests/fsm/in20.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; + +# out of order is okay +end: a = [ 7, 53, 999 ]; + diff --git a/tests/fsm/in21.fsm b/tests/fsm/in21.fsm new file mode 100644 index 000000000..f53082d14 --- /dev/null +++ b/tests/fsm/in21.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; + +# positive integers only +end: a = [ -1 ]; + diff --git a/tests/fsm/in22.fsm b/tests/fsm/in22.fsm new file mode 100644 index 000000000..c376a9d28 --- /dev/null +++ b/tests/fsm/in22.fsm @@ -0,0 +1,11 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +a -> b 'a'; + +start: a; +end: b = [ 7 ]; + diff --git a/tests/fsm/in3.fsm b/tests/fsm/in3.fsm new file mode 100644 index 000000000..b3f86c37b --- /dev/null +++ b/tests/fsm/in3.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# not a valid identifier ++; + diff --git a/tests/fsm/in4.fsm b/tests/fsm/in4.fsm new file mode 100644 index 000000000..e1edb77b8 --- /dev/null +++ b/tests/fsm/in4.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# syntax error +abc -> + diff --git a/tests/fsm/in5.fsm b/tests/fsm/in5.fsm new file mode 100644 index 000000000..8550f0566 --- /dev/null +++ b/tests/fsm/in5.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# syntax error +-> def; + diff --git a/tests/fsm/in6.fsm b/tests/fsm/in6.fsm new file mode 100644 index 000000000..9f6c3c3e8 --- /dev/null +++ b/tests/fsm/in6.fsm @@ -0,0 +1,8 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +x -> y; + diff --git a/tests/fsm/in7.fsm b/tests/fsm/in7.fsm new file mode 100644 index 000000000..09d508a27 --- /dev/null +++ b/tests/fsm/in7.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# implicit state +start: x; + diff --git a/tests/fsm/in8.fsm b/tests/fsm/in8.fsm new file mode 100644 index 000000000..7760b6e3c --- /dev/null +++ b/tests/fsm/in8.fsm @@ -0,0 +1,12 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# explicitly created states +x; +y; + +start: x; + diff --git a/tests/fsm/in9.fsm b/tests/fsm/in9.fsm new file mode 100644 index 000000000..e7cbbcc0d --- /dev/null +++ b/tests/fsm/in9.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +# missing separator +a b c + diff --git a/tests/fsm/out0.fsm b/tests/fsm/out0.fsm new file mode 100644 index 000000000..e69de29bb diff --git a/tests/fsm/out1.fsm b/tests/fsm/out1.fsm new file mode 100644 index 000000000..e69de29bb diff --git a/tests/fsm/out10.err b/tests/fsm/out10.err new file mode 100644 index 000000000..412679b24 --- /dev/null +++ b/tests/fsm/out10.err @@ -0,0 +1 @@ +9:1: Syntax error: expected ';' diff --git a/tests/fsm/out11.err b/tests/fsm/out11.err new file mode 100644 index 000000000..d5b538786 --- /dev/null +++ b/tests/fsm/out11.err @@ -0,0 +1 @@ +8:8: Syntax error: expected ',' diff --git a/tests/fsm/out12.err b/tests/fsm/out12.err new file mode 100644 index 000000000..ebbbb9d1b --- /dev/null +++ b/tests/fsm/out12.err @@ -0,0 +1 @@ +8:1: Syntax error diff --git a/tests/fsm/out13.err b/tests/fsm/out13.err new file mode 100644 index 000000000..ebbbb9d1b --- /dev/null +++ b/tests/fsm/out13.err @@ -0,0 +1 @@ +8:1: Syntax error diff --git a/tests/fsm/out14.err b/tests/fsm/out14.err new file mode 100644 index 000000000..f7e4f861b --- /dev/null +++ b/tests/fsm/out14.err @@ -0,0 +1 @@ +8:3: Syntax error diff --git a/tests/fsm/out15.err b/tests/fsm/out15.err new file mode 100644 index 000000000..fbca0e9a6 --- /dev/null +++ b/tests/fsm/out15.err @@ -0,0 +1 @@ +10:12: Syntax error diff --git a/tests/fsm/out16.fsm b/tests/fsm/out16.fsm new file mode 100644 index 000000000..49f89e1ca --- /dev/null +++ b/tests/fsm/out16.fsm @@ -0,0 +1,8 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; +end: a; diff --git a/tests/fsm/out17.err b/tests/fsm/out17.err new file mode 100644 index 000000000..fbca0e9a6 --- /dev/null +++ b/tests/fsm/out17.err @@ -0,0 +1 @@ +10:12: Syntax error diff --git a/tests/fsm/out18.err b/tests/fsm/out18.err new file mode 100644 index 000000000..fbca0e9a6 --- /dev/null +++ b/tests/fsm/out18.err @@ -0,0 +1 @@ +10:12: Syntax error diff --git a/tests/fsm/out19.fsm b/tests/fsm/out19.fsm new file mode 100644 index 000000000..11c504879 --- /dev/null +++ b/tests/fsm/out19.fsm @@ -0,0 +1,8 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; +end: a = [ 0 ]; diff --git a/tests/fsm/out2.fsm b/tests/fsm/out2.fsm new file mode 100644 index 000000000..5e711912e --- /dev/null +++ b/tests/fsm/out2.fsm @@ -0,0 +1,7 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +0; 1; 2; 3; 4; diff --git a/tests/fsm/out20.fsm b/tests/fsm/out20.fsm new file mode 100644 index 000000000..71556c552 --- /dev/null +++ b/tests/fsm/out20.fsm @@ -0,0 +1,8 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: a; +end: a = [ 0, 1, 2 ]; diff --git a/tests/fsm/out21.err b/tests/fsm/out21.err new file mode 100644 index 000000000..fbca0e9a6 --- /dev/null +++ b/tests/fsm/out21.err @@ -0,0 +1 @@ +10:12: Syntax error diff --git a/tests/fsm/out22.fsm b/tests/fsm/out22.fsm new file mode 100644 index 000000000..50f1bb868 --- /dev/null +++ b/tests/fsm/out22.fsm @@ -0,0 +1,9 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +0 -> 1 'a'; +start: 0; +end: 1 = [ 0 ]; diff --git a/tests/fsm/out3.err b/tests/fsm/out3.err new file mode 100644 index 000000000..ebbbb9d1b --- /dev/null +++ b/tests/fsm/out3.err @@ -0,0 +1 @@ +8:1: Syntax error diff --git a/tests/fsm/out4.err b/tests/fsm/out4.err new file mode 100644 index 000000000..31fa45171 --- /dev/null +++ b/tests/fsm/out4.err @@ -0,0 +1 @@ +8:7: Syntax error diff --git a/tests/fsm/out5.err b/tests/fsm/out5.err new file mode 100644 index 000000000..ebbbb9d1b --- /dev/null +++ b/tests/fsm/out5.err @@ -0,0 +1 @@ +8:1: Syntax error diff --git a/tests/fsm/out6.fsm b/tests/fsm/out6.fsm new file mode 100644 index 000000000..b673566f0 --- /dev/null +++ b/tests/fsm/out6.fsm @@ -0,0 +1,7 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +0 -> 1; diff --git a/tests/fsm/out7.fsm b/tests/fsm/out7.fsm new file mode 100644 index 000000000..3d4653a70 --- /dev/null +++ b/tests/fsm/out7.fsm @@ -0,0 +1,7 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +start: 0; diff --git a/tests/fsm/out8.fsm b/tests/fsm/out8.fsm new file mode 100644 index 000000000..86110f4ba --- /dev/null +++ b/tests/fsm/out8.fsm @@ -0,0 +1,10 @@ +# +# Copyright 2008-2024 Katherine Flavel +# +# See LICENCE for the full copyright terms. +# + +0; +1; + +start: 0; diff --git a/tests/fsm/out9.err b/tests/fsm/out9.err new file mode 100644 index 000000000..f7e4f861b --- /dev/null +++ b/tests/fsm/out9.err @@ -0,0 +1 @@ +8:3: Syntax error diff --git a/tests/gen/gtest.c b/tests/gen/gtest.c index 140407943..124c8be1b 100644 --- a/tests/gen/gtest.c +++ b/tests/gen/gtest.c @@ -58,21 +58,20 @@ gtest_matches_cb(const struct fsm *fsm, m->found = true; #define ID_BUF_COUNT 1 - fsm_end_id_t id_buf[ID_BUF_COUNT]; - size_t written; - enum fsm_getendids_res gres = fsm_getendids(fsm, - end_state, ID_BUF_COUNT, id_buf, &written); + fsm_end_id_t ids[ID_BUF_COUNT]; + int gres = fsm_endid_get(fsm, + end_state, ID_BUF_COUNT, ids); - if (gres != FSM_GETENDIDS_FOUND) { + if (gres != 1) { fprintf(stderr, - "ERROR: fsm_getendids: returned %d\n", + "ERROR: fsm_endid_get: returned %d\n", gres); return FSM_GENERATE_MATCHES_CB_RES_HALT; } - if (written != 1 || id_buf[0] != m_i) { + if (fsm_endid_count(fsm, end_state) != 1 || ids[0] != m_i) { fprintf(stderr, "ERROR: endid mismatch, expected %zu, got %u\n", - m_i, id_buf[0]); + m_i, ids[0]); return FSM_GENERATE_MATCHES_CB_RES_HALT; } diff --git a/tests/re_strings/testutil.c b/tests/re_strings/testutil.c index 4f4678b0d..50cc21be0 100644 --- a/tests/re_strings/testutil.c +++ b/tests/re_strings/testutil.c @@ -12,7 +12,7 @@ static struct fsm_options opt; #define MAX_INPUTS 100 -static fsm_end_id_t id_buf[MAX_INPUTS]; +static fsm_end_id_t ids[MAX_INPUTS]; int run_test(const char **strings) @@ -47,13 +47,12 @@ run_test(const char **strings) const int res = fsm_exec(fsm, fsm_sgetc, string, &end, NULL); assert(res > 0); /* match */ - size_t written; - enum fsm_getendids_res eres = fsm_getendids(fsm, end, - MAX_INPUTS, id_buf, &written); - assert(eres == FSM_GETENDIDS_FOUND); + int eres = fsm_endid_get(fsm, end, + MAX_INPUTS, ids); + assert(eres == 1); bool found = false; - for (size_t i = 0; i < written; i++) { - if (id_buf[i] == id) { + for (size_t i = 0; i < fsm_endid_count(fsm, end); i++) { + if (ids[i] == id) { found = true; break; }
S%u%s
end id"); + + for (size_t i = 0; i < cs->endids.count; i++) { + fprintf(f, "#%u", cs->endids.ids[i]); + + if (i < cs->endids.count - 1) { + fprintf(f, " "); + } + } + + fprintf(f, "
example"); escputs(f, opt, dot_escputc_html, cs->example); @@ -199,6 +214,18 @@ print_cs(FILE *f, const struct fsm_options *opt, /* TODO: leaf callback for dot output */ + /* showing endleaf in addition to existing content */ + if (cs->isend && opt->endleaf != NULL) { + fprintf(f, "\t\t
"); + if (-1 == opt->endleaf(f, + cs->endids.ids, cs->endids.count, + opt->endleaf_opaque)) + { + return -1; + } + fprintf(f, "