2023-03-05 21:55:20 +00:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "apfl.h"
|
|
|
|
|
#include "bytecode.h"
|
|
|
|
|
#include "compile.h"
|
|
|
|
|
#include "format.h"
|
|
|
|
|
#include "gc.h"
|
|
|
|
|
#include "strings.h"
|
|
|
|
|
|
|
|
|
|
struct c_writer_data {
|
|
|
|
|
struct apfl_io_writer w;
|
|
|
|
|
size_t written_len;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const unsigned char hex[] = {
|
|
|
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
|
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
write_as_c_source(void *opaque, const unsigned char *buf, size_t len)
|
|
|
|
|
{
|
|
|
|
|
struct c_writer_data *data = opaque;
|
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
|
if (data->written_len % 16 == 0) {
|
|
|
|
|
if (!apfl_io_write_byte(data->w, '\n')) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned char out[] = {'0', 'x', hex[(buf[i] >> 4) & 0x0F], hex[buf[i] & 0x0F], ','};
|
|
|
|
|
|
|
|
|
|
if (!apfl_io_write_string_view(
|
|
|
|
|
data->w,
|
|
|
|
|
(struct apfl_string_view) { .bytes = out, .len = sizeof(out), }
|
|
|
|
|
)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(data->written_len)++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
c_source_prelude(struct apfl_io_writer w)
|
|
|
|
|
{
|
|
|
|
|
return apfl_io_write_string(
|
|
|
|
|
w,
|
|
|
|
|
"#include <stddef.h>\n"
|
|
|
|
|
// TODO: This is a bit hackish, the generated C code should include
|
|
|
|
|
// apfl.h instead of declaring the string view struct itself. However,
|
|
|
|
|
// since the code is generated, it does not live in the same directory
|
|
|
|
|
// as apfl.h, so our usual `#include "apfl.h"` doesn't work.
|
|
|
|
|
"struct apfl_string_view {\n"
|
|
|
|
|
" const unsigned char *bytes;\n"
|
|
|
|
|
" size_t len;\n"
|
|
|
|
|
"};\n"
|
|
|
|
|
"static const unsigned char bytecode[] = {"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
c_source_epilogue(struct apfl_io_writer w, const char *function_name)
|
|
|
|
|
{
|
|
|
|
|
return apfl_io_write_string(w,
|
|
|
|
|
"\n};\n"
|
|
|
|
|
"struct apfl_string_view\n"
|
|
|
|
|
)
|
|
|
|
|
&& apfl_io_write_string(w, function_name)
|
|
|
|
|
&& apfl_io_write_string(w,
|
|
|
|
|
"(void)\n"
|
|
|
|
|
"{\n"
|
|
|
|
|
" return (struct apfl_string_view) {\n"
|
|
|
|
|
" .bytes = bytecode,\n"
|
|
|
|
|
" .len = sizeof(bytecode),\n"
|
|
|
|
|
" };\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
get_next_string_from_arg(const char *progname, const char ***argpp)
|
|
|
|
|
{
|
|
|
|
|
if (**argpp == NULL) {
|
|
|
|
|
fprintf(stderr, "Usage: %s [-c function_name] input output\n", progname);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *filename = **argpp;
|
|
|
|
|
(*argpp)++;
|
|
|
|
|
return filename;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FILE *
|
|
|
|
|
openfile(const char *progname, const char *filename, const char *mode)
|
|
|
|
|
{
|
|
|
|
|
FILE *f = fopen(filename, mode);
|
|
|
|
|
if (f == NULL) {
|
|
|
|
|
fprintf(stderr, "%s: Could not open %s: %s\n", progname, filename, strerror(errno));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
closefile(FILE *f)
|
|
|
|
|
{
|
|
|
|
|
if (f != NULL) {
|
|
|
|
|
fclose(f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-23 19:29:38 +00:00
|
|
|
struct protected_compiling_data {
|
|
|
|
|
const char *name;
|
|
|
|
|
struct apfl_io_reader *r;
|
|
|
|
|
struct apfl_io_writer *w;
|
|
|
|
|
};
|
2023-03-05 21:55:20 +00:00
|
|
|
|
2023-11-23 19:29:38 +00:00
|
|
|
static void
|
|
|
|
|
protected_compiling(apfl_ctx ctx, void *opaque)
|
|
|
|
|
{
|
|
|
|
|
struct protected_compiling_data *data = opaque;
|
2023-03-05 21:55:20 +00:00
|
|
|
|
2023-11-23 19:29:38 +00:00
|
|
|
apfl_push_const_string(ctx, data->name);
|
|
|
|
|
apfl_load(ctx, apfl_io_reader_as_source_reader(data->r), -1);
|
|
|
|
|
apfl_bytecode_save(ctx, *data->w, -1);
|
2023-03-05 21:55:20 +00:00
|
|
|
}
|
|
|
|
|
|
2023-11-23 19:29:38 +00:00
|
|
|
#define MAIN_TRY_FMT(x) if (!(x)) { goto error; }
|
|
|
|
|
|
2023-03-05 21:55:20 +00:00
|
|
|
int
|
|
|
|
|
main(int argc, const char *argv[])
|
|
|
|
|
{
|
|
|
|
|
(void)argc;
|
|
|
|
|
const char **argp = argv+1;
|
|
|
|
|
|
|
|
|
|
FILE *in = NULL;
|
|
|
|
|
FILE *out = NULL;
|
|
|
|
|
|
|
|
|
|
const char *c_function_name = NULL;
|
|
|
|
|
if (*argp != NULL && apfl_string_eq(*argp, "-c")) {
|
|
|
|
|
argp++;
|
|
|
|
|
if ((c_function_name = get_next_string_from_arg(argv[0], &argp)) == NULL) {
|
2023-11-23 19:29:38 +00:00
|
|
|
goto error_before_ctx;
|
2023-03-05 21:55:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *name_in = NULL;
|
|
|
|
|
const char *name_out = NULL;
|
|
|
|
|
if (
|
|
|
|
|
(name_in = get_next_string_from_arg(argv[0], &argp)) == NULL
|
|
|
|
|
|| (name_out = get_next_string_from_arg(argv[0], &argp)) == NULL
|
|
|
|
|
) {
|
2023-11-23 19:29:38 +00:00
|
|
|
goto error_before_ctx;
|
2023-03-05 21:55:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rv = 1;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
(in = openfile(argv[0], name_in, "rb")) == NULL
|
|
|
|
|
|| (out = openfile(argv[0], name_out, "wb")) == NULL
|
|
|
|
|
) {
|
2023-11-23 19:29:38 +00:00
|
|
|
goto error_before_ctx;
|
2023-03-05 21:55:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct apfl_io_reader r = apfl_io_file_reader(in);
|
|
|
|
|
struct apfl_io_writer w_raw = apfl_io_file_writer(out);
|
|
|
|
|
|
|
|
|
|
if (c_function_name != NULL && !c_source_prelude(w_raw)) {
|
|
|
|
|
fprintf(stderr, "%s: IO error\n", argv[0]);
|
2023-11-23 19:29:38 +00:00
|
|
|
goto error_before_ctx;
|
2023-03-05 21:55:20 +00:00
|
|
|
}
|
|
|
|
|
|
2023-11-23 19:29:38 +00:00
|
|
|
struct apfl_io_writer w_err = apfl_io_file_writer(stderr);
|
2023-03-05 21:55:20 +00:00
|
|
|
struct apfl_io_writer bytecode_writer = w_raw;
|
|
|
|
|
struct c_writer_data c_writer_data = {
|
|
|
|
|
.w = w_raw,
|
|
|
|
|
.written_len = 0,
|
|
|
|
|
};
|
|
|
|
|
if (c_function_name != NULL) {
|
|
|
|
|
bytecode_writer = (struct apfl_io_writer) {
|
|
|
|
|
.opaque = &c_writer_data,
|
|
|
|
|
.write = write_as_c_source,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-23 19:29:38 +00:00
|
|
|
apfl_ctx ctx = apfl_ctx_new((struct apfl_config) {
|
|
|
|
|
.allocator = apfl_allocator_default(),
|
|
|
|
|
.output_writer = apfl_io_file_writer(stdout),
|
|
|
|
|
.no_standard_modules = true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
|
fprintf(stderr, "Could not init context\n");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct protected_compiling_data data = {
|
|
|
|
|
.name = name_in,
|
|
|
|
|
.r = &r,
|
|
|
|
|
.w = &bytecode_writer,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (apfl_do_protected(ctx, protected_compiling, &data, NULL)) {
|
|
|
|
|
case APFL_RESULT_OK :
|
|
|
|
|
break;
|
|
|
|
|
case APFL_RESULT_ERR:
|
|
|
|
|
MAIN_TRY_FMT(apfl_io_write_string(w_err, "Error occurred during compilation:\n"));
|
|
|
|
|
if (apfl_get_type(ctx, -1) == APFL_VALUE_STRING) {
|
|
|
|
|
MAIN_TRY_FMT(apfl_io_write_string(w_err, apfl_get_string(ctx, -1)));
|
|
|
|
|
} else {
|
|
|
|
|
MAIN_TRY_FMT(apfl_debug_print_val(ctx, -1, w_err));
|
|
|
|
|
}
|
|
|
|
|
MAIN_TRY_FMT(apfl_io_write_byte(w_err, '\n'));
|
|
|
|
|
break;
|
|
|
|
|
case APFL_RESULT_ERRERR:
|
|
|
|
|
MAIN_TRY_FMT(apfl_io_write_string(w_err, "Error occurred during error handling.\n"));
|
|
|
|
|
break;
|
|
|
|
|
case APFL_RESULT_ERR_ALLOC:
|
|
|
|
|
MAIN_TRY_FMT(apfl_io_write_string(w_err, "Fatal: Could not allocate memory.\n"));
|
2023-03-05 21:55:20 +00:00
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c_function_name != NULL && !c_source_epilogue(w_raw, c_function_name)) {
|
|
|
|
|
fprintf(stderr, "%s: IO error\n", argv[0]);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
|
error:
|
2023-11-23 19:29:38 +00:00
|
|
|
apfl_ctx_destroy(ctx);
|
|
|
|
|
error_before_ctx:
|
2023-03-05 21:55:20 +00:00
|
|
|
closefile(in);
|
|
|
|
|
closefile(out);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|