Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement AMBIG_MULTIPLE for llvm, Rust, go, and the vmops dump #486

Merged
merged 22 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading