Skip to content

Commit

Permalink
Merge pull request #486 from katef/kate/more-multi
Browse files Browse the repository at this point in the history
Implement AMBIG_MULTIPLE for llvm, Rust, go, and the vmops dump
  • Loading branch information
katef authored Aug 16, 2024
2 parents 62d3b3b + ab0a411 commit 0a36f1b
Show file tree
Hide file tree
Showing 25 changed files with 1,201 additions and 736 deletions.
16 changes: 15 additions & 1 deletion include/fsm/print.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ struct fsm_hooks {
int (*reject)(FILE *, const struct fsm_options *opt,
void *lang_opaque, void *hook_opaque);

int (*comment)(FILE *, const struct fsm_options *opt,
const fsm_end_id_t *ids, size_t count,
void *hook_opaque);

/* only called for AMBIG_ERROR; see opt.ambig */
int (*conflict)(FILE *, const struct fsm_options *opt,
const fsm_end_id_t *ids, size_t count,
Expand All @@ -83,7 +87,17 @@ struct fsm_hooks {

/*
* Print an FSM to the given file stream. The output is written in the format
* specified.
* specified by the lang enum.
*
* Not all languages support all options, and fsm_print will ENOTSUP where
* these are not possible. This is different to when an option is possible
* but simply not yet implemented, where fsm_print() will print a message
* to stderr and exit.
*
* The code generation for the typical case of matching input requires the FSM
* to be a DFA, and will EINVAL if the FSM is not a DFA. As opposed to e.g.
* FSM_PRINT_API, which generates code for other purposes, and does not place
* particular expecations on the FSM.
*
* The output options may be NULL, indicating to use defaults.
*
Expand Down
48 changes: 46 additions & 2 deletions src/libfsm/print.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "print.h"
#include "internal.h"

#include "vm/retlist.h"
#include "vm/vm.h"
#include "print/ir.h"

Expand Down Expand Up @@ -81,6 +82,31 @@ print_hook_accept(FILE *f,
return 0;
}

int
print_hook_comment(FILE *f,
const struct fsm_options *opt,
const struct fsm_hooks *hooks,
const fsm_end_id_t *ids, size_t count)
{
assert(f != NULL);
assert(opt != NULL);
assert(hooks != NULL);

if (opt->ambig == AMBIG_ERROR) {
assert(count <= 1);
}

if (opt->comments && hooks->comment != NULL) {
/* this space is a polyglot */
fprintf(f, " ");

return hooks->comment(f, opt, ids, count,
hooks->hook_opaque);
}

return 0;
}

int
print_hook_reject(FILE *f,
const struct fsm_options *opt,
Expand Down Expand Up @@ -179,6 +205,7 @@ print_conflicts(FILE *f, const struct fsm *fsm,
assert(res == 1);

// TODO: de-duplicate by ids[], so we don't call the conflict hook an unneccessary number of times
// TODO: now i think this is the same as calling once per retlist entry

/*
* The conflict hook is called here (rather in the caller),
Expand Down Expand Up @@ -336,20 +363,37 @@ fsm_print(FILE *f, const struct fsm *fsm,
goto done;
}

/*
* We're building the retlist here based on the ir.
* I think we could build the retlist earlier instead,
* and then point at the struct ret entries from the ir,
* and then dfavm_compile_ir() would pick those up from there.
* But for now this is good.
*/
struct ret_list retlist;

if (!build_retlist(&retlist, ir)) {
free_ir(fsm, ir);
goto error;
}

a = zero;

/* TODO: non-const a */
if (!dfavm_compile_ir(&a, ir, vm_opts)) {
if (!dfavm_compile_ir(&a, ir, &retlist, vm_opts)) {
free_retlist(&retlist);
free_ir(fsm, ir);
return -1;
}

if (print_vm != NULL) {
r = print_vm(f, opt, hooks, a.linked);
r = print_vm(f, opt, hooks, &retlist, a.linked);
}

dfavm_opasm_finalize_op(&a);

free_retlist(&retlist);

done:

if (ir != NULL) {
Expand Down
8 changes: 8 additions & 0 deletions src/libfsm/print.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct fsm_options;
struct fsm_hooks;
struct ir;
struct dfavm_op_ir;
struct ret_list;

int
print_hook_args(FILE *f,
Expand All @@ -31,6 +32,12 @@ print_hook_accept(FILE *f,
void *lang_opaque, void *hook_opaque),
void *lang_opaque);

int
print_hook_comment(FILE *f,
const struct fsm_options *opt,
const struct fsm_hooks *hooks,
const fsm_end_id_t *ids, size_t count);

int
print_hook_reject(FILE *f,
const struct fsm_options *opt,
Expand Down Expand Up @@ -59,6 +66,7 @@ typedef int ir_print_f(FILE *f,
typedef int vm_print_f(FILE *f,
const struct fsm_options *opt,
const struct fsm_hooks *hooks,
const struct ret_list *retlist,
struct dfavm_op_ir *ops);

vm_print_f fsm_print_amd64_att;
Expand Down
2 changes: 1 addition & 1 deletion src/libfsm/print/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ fsm_print_api(FILE *f,
} else {
fprintf(f, "\tfor (i = 0x%02x; i <= 0x%02x; i++) {",
(unsigned int) lo, (unsigned int) hi - 1);
if (rangeclass(lo, hi - 1)) {
if (opt->comments && rangeclass(lo, hi - 1)) {
fprintf(f, " /* '%c' .. '%c' */", (unsigned char) lo, (unsigned char) hi - 1);
}
fprintf(f, "\n");
Expand Down
26 changes: 21 additions & 5 deletions src/libfsm/print/awk.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "libfsm/internal.h"
#include "libfsm/print.h"

#include "libfsm/vm/retlist.h"
#include "libfsm/vm/vm.h"

#define START UINT32_MAX
Expand Down Expand Up @@ -156,10 +157,21 @@ print_end(FILE *f, const struct dfavm_op_ir *op,
return print_hook_reject(f, opt, hooks, default_reject, NULL);

case VM_END_SUCC:
return print_hook_accept(f, opt, hooks,
op->endids.ids, op->endids.count,
if (-1 == print_hook_accept(f, opt, hooks,
op->ret->ids, op->ret->count,
default_accept,
NULL);
NULL))
{
return -1;
}

if (-1 == print_hook_comment(f, opt, hooks,
op->ret->ids, op->ret->count))
{
return -1;
}

return 0;

default:
assert(!"unreached");
Expand All @@ -186,6 +198,7 @@ static int
fsm_print_awkfrag(FILE *f,
const struct fsm_options *opt,
const struct fsm_hooks *hooks,
const struct ret_list *retlist,
struct dfavm_op_ir *ops,
const char *cp, const char *prefix)
{
Expand All @@ -194,6 +207,7 @@ fsm_print_awkfrag(FILE *f,
assert(f != NULL);
assert(opt != NULL);
assert(hooks != NULL);
assert(retlist != NULL);
assert(cp != NULL);
assert(prefix != NULL);

Expand Down Expand Up @@ -289,6 +303,7 @@ int
fsm_print_awk(FILE *f,
const struct fsm_options *opt,
const struct fsm_hooks *hooks,
const struct ret_list *retlist,
struct dfavm_op_ir *ops)
{
const char *prefix;
Expand All @@ -297,6 +312,7 @@ fsm_print_awk(FILE *f,
assert(f != NULL);
assert(opt != NULL);
assert(hooks != NULL);
assert(retlist != NULL);

if (opt->prefix != NULL) {
prefix = opt->prefix;
Expand All @@ -311,7 +327,7 @@ fsm_print_awk(FILE *f,
}

if (opt->fragment) {
if (-1 == fsm_print_awkfrag(f, opt, hooks, ops, cp, prefix)) {
if (-1 == fsm_print_awkfrag(f, opt, hooks, retlist, ops, cp, prefix)) {
return -1;
}
} else {
Expand All @@ -333,7 +349,7 @@ fsm_print_awk(FILE *f,

fprintf(f, ", l, c) {\n");

if (-1 == fsm_print_awkfrag(f, opt, hooks, ops, cp, prefix)) {
if (-1 == fsm_print_awkfrag(f, opt, hooks, retlist, ops, cp, prefix)) {
return -1;
}

Expand Down
40 changes: 31 additions & 9 deletions src/libfsm/print/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,17 @@ print_ids(FILE *f,
return -1;
}

fprintf(f, "return %u;", ids[0]);
break;
/* fallthrough */

case AMBIG_EARLIEST:
/*
* The libfsm api guarentees these ids are unique,
* and only appear once each, and are sorted.
*/
fprintf(f, "return %u;", ids[0]);
fprintf(f, "{\n");
fprintf(f, "\t\t*id = %u;\n", ids[0]);
fprintf(f, "\t\treturn 1;\n");
fprintf(f, "\t}");
break;

case AMBIG_MULTIPLE:
Expand All @@ -101,7 +103,7 @@ print_ids(FILE *f,
fprintf(f, " };\n");
fprintf(f, "\t\t*ids = a;\n");
fprintf(f, "\t\t*count = %zu;\n", count);
fprintf(f, "\t\treturn 0;\n");
fprintf(f, "\t\treturn 1;\n");
fprintf(f, "\t}");
break;

Expand Down Expand Up @@ -352,12 +354,18 @@ print_endstates(FILE *f,

/* no end states */
if (!ir_hasend(ir)) {
fprintf(f, "\treturn 0; /* unexpected EOT */\n");
fprintf(f, "\treturn 0;");
if (opt->comments) {
fprintf(f, " /* unexpected EOT */");
}
fprintf(f, "\n");
return 0;
}

/* usual case */
fprintf(f, "\t/* end states */\n");
if (opt->comments) {
fprintf(f, "\t/* end states */\n");
}
fprintf(f, "\tswitch (state) {\n");
for (i = 0; i < ir->n; i++) {
if (!ir->states[i].isend) {
Expand All @@ -374,6 +382,12 @@ print_endstates(FILE *f,
return -1;
}

if (-1 == print_hook_comment(f, opt, hooks,
ir->states[i].endids.ids, ir->states[i].endids.count))
{
return -1;
}

fprintf(f, "\n");
}

Expand Down Expand Up @@ -410,7 +424,7 @@ fsm_print_cfrag(FILE *f, const struct ir *ir,
fprintf(f, " /* e.g. \"");
escputs(f, opt, c_escputc_str, ir->states[i].example);
fprintf(f, "\" */");
} else if (i == ir->start) {
} else if (i == ir->start && opt->comments) {
fprintf(f, " /* start */");
}
}
Expand All @@ -423,7 +437,11 @@ fsm_print_cfrag(FILE *f, const struct ir *ir,
fprintf(f, "\n");
}
fprintf(f, "\t\tdefault:\n");
fprintf(f, "\t\t\t; /* unreached */\n");
fprintf(f, "\t\t\t;");
if (opt->comments) {
fprintf(f, " /* unreached */");
}
fprintf(f, "\n");
fprintf(f, "\t\t}\n");

if (ferror(f)) {
Expand Down Expand Up @@ -595,7 +613,11 @@ fsm_print_c(FILE *f,
}

if (ir->n == 0) {
fprintf(f, "\treturn 0; /* no matches */\n");
fprintf(f, "\treturn 0;");
if (opt->comments) {
fprintf(f, " /* no matches */");
}
fprintf(f, "\n");
} else {
if (-1 == fsm_print_c_body(f, ir, opt, hooks)) {
return -1;
Expand Down
12 changes: 11 additions & 1 deletion src/libfsm/print/dot.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,22 @@ print_dotfrag(FILE *f,
return -1;
}

if (opt->comments && hooks->comment != NULL) {
fprintf(f, ",");

if (-1 == print_hook_comment(f, opt, hooks,
ids, count))
{
return -1;
}
}

fprintf(f, " ];\n");

f_free(fsm->alloc, ids);
}

/* TODO: show example here, unless !opt->comments */
/* TODO: comment example per state */

if (-1 == print_state(f, opt, hooks, fsm, prefix, s)) {
return -1;
Expand Down
8 changes: 7 additions & 1 deletion src/libfsm/print/fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,13 @@ fsm_print_fsm(FILE *f,
if (-1 == print_hook_accept(f, opt, hooks,
ids, count,
default_accept,
NULL))
NULL))
{
return -1;
}

if (-1 == print_hook_comment(f, opt, hooks,
ids, count))
{
return -1;
}
Expand Down
Loading

0 comments on commit 0a36f1b

Please sign in to comment.