summaryrefslogtreecommitdiff
path: root/tools/kons2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/kons2c.c')
-rw-r--r--tools/kons2c.c216
1 files changed, 13 insertions, 203 deletions
diff --git a/tools/kons2c.c b/tools/kons2c.c
index 8cacbc8..2a53520 100644
--- a/tools/kons2c.c
+++ b/tools/kons2c.c
@@ -25,31 +25,16 @@
/*
* usage: kons2c [-n name] [-split rows] <script.kons> <output prefix>
- * turns konscript text into C. any converter can write konscript text, this is the one place that writes C from it.
- *
- * the text goes through the real parser first, so every jump lands on a label that is there, and nothing is written if it
- * doesn't parse. what comes out is only constant data: a list of kon_cmd_t, a sorted list of labels and a find function.
- * strings are written as literals where everything but plain printable characters is an octal escape, so what is in the
- * script can't be anything but text to the compiler. there is no pointer arithmetic, no generated logic and nothing to overrun
- *
- * writes prefix.h and prefix.c, and with -split also prefix_0.inc, prefix_1.inc and so on that prefix.c includes inside
- * the one array, so a big script is several files for the editor and one list for the program
+ * konscript text to C, for scripts written by hand. the converters write C themselves through konscriptc.h
*/
-#include "konscript.h"
+#define KONSCRIPTC_IMPLEMENTATION
+#include "konscriptc.h"
-#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-static const char *const opNames[] = {
- "KON_OP_END", "KON_OP_SAY", "KON_OP_MENU", "KON_OP_OPTION", "KON_OP_JUMP", "KON_OP_SWITCH", "KON_OP_VAR",
- "KON_OP_IFSWITCH", "KON_OP_IFVAR", "KON_OP_WAIT", "KON_OP_HOST", "KON_OP_CALL", "KON_OP_RETURN"
-};
-
-/*** reading ***/
-
static char *readFile(const char *path, size_t *size)
{
FILE *f = fopen(path, "rb");
@@ -72,86 +57,14 @@ static char *readFile(const char *path, size_t *size)
return text;
}
-static int compareLabels(const void *a, const void *b)
-{
- return strcmp(((const kon_scriptLabel_t *)a)->name, ((const kon_scriptLabel_t *)b)->name);
-}
-
-/*** writing ***/
-
-static int putString(FILE *f, const char *s)
-{
- size_t i, column = 0;
-
- if (!s) return fputs("NULL", f) >= 0;
- fputc('"', f);
- for (i = 0; s[i]; i++) {
- unsigned char c = (unsigned char)s[i];
-
- if (column >= 100) {
- fputs("\"\n\t\t\"", f);
- column = 0;
- }
- if (c == '"' || c == '\\' || c == '?') {
- fprintf(f, "\\%c", c);
- column += 2;
- } else if (c == '\n' || c == '\t') {
- fputs(c == '\n' ? "\\n" : "\\t", f);
- column += 2;
- } else if (c >= 0x20 && c < 0x7F) {
- fputc(c, f);
- column++;
- } else {
- fprintf(f, "\\%03o", c);
- column += 4;
- }
- }
- fputc('"', f);
- return 1;
-}
-
-static void putRow(FILE *f, const kon_cmd_t *c)
-{
- fprintf(f, "\t{%s, %d, %d, %d, %d, ", opNames[c->op], c->a, c->b, c->c, c->d);
- putString(f, c->text);
- fputs("},\n", f);
-}
-
-static void identifier(char *out, size_t size, const char *path)
-{
- const char *base = strrchr(path, '/');
- size_t i, n = 0;
-
- base = base ? base + 1 : path;
- for (i = 0; base[i] && base[i] != '.' && n + 1 < size; i++) out[n++] = isalnum((unsigned char)base[i]) ? (char)tolower((unsigned char)base[i]) : '_';
- out[n] = '\0';
- if (!n || isdigit((unsigned char)out[0])) {
- memmove(out + 1, out, n + 1 < size ? n + 1 : size - 1);
- out[0] = 'k';
- }
-}
-
-static FILE *create(const char *prefix, const char *suffix)
-{
- char path[1024];
- FILE *f;
-
- if (snprintf(path, sizeof path, "%s%s", prefix, suffix) >= (int)sizeof path) return NULL;
- f = fopen(path, "wb");
- if (!f) fprintf(stderr, "cannot write %s\n", path);
- return f;
-}
-
int main(int argc, char **argv)
{
- char name[64] = "", upper[64];
+ char name[64] = "", error[200];
const char *input = NULL, *prefix = NULL;
- int split = 0, i, rows, lines = 1;
- size_t size, k;
+ int split = 0, i;
+ size_t size;
char *source;
- kon_scriptBuild_t b;
- kon_cmd_t *cmds;
- FILE *f;
+ konsc_result_t result;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-n") && i + 1 < argc) {
@@ -164,125 +77,22 @@ int main(int argc, char **argv)
prefix = argv[i];
}
}
- if (!input || !prefix || split < 0) {
+ if (!input || !prefix) {
fprintf(stderr, "usage: kons2c [-n name] [-split rows] <script.kons> <output prefix>\n");
return 2;
}
- if (!name[0]) identifier(name, sizeof name, prefix);
- for (k = 0; name[k]; k++) {
- if (!isalnum((unsigned char)name[k]) && name[k] != '_') {
- fprintf(stderr, "the name has to be letters, digits and _\n");
- return 2;
- }
- upper[k] = (char)toupper((unsigned char)name[k]);
- }
- upper[k] = '\0';
- if (isdigit((unsigned char)name[0])) {
- fprintf(stderr, "the name can't start with a digit\n");
- return 2;
- }
-
+ if (!name[0]) konsc_name(name, sizeof name, prefix);
source = readFile(input, &size);
if (!source) {
fprintf(stderr, "cannot read %s\n", input);
return 1;
}
- for (k = 0; k < size; k++) {
- if (source[k] == '\n') lines++;
- }
-
- memset(&b, 0, sizeof b);
- b.maxCmds = lines + 2;
- b.maxLabels = lines + 2;
- b.poolSize = (int)(size + 16);
- b.hashSize = 16;
- while (b.hashSize < 2 * b.maxLabels) b.hashSize *= 2;
- cmds = malloc((size_t)b.maxCmds * sizeof *cmds);
- b.cmds = cmds;
- b.pool = malloc((size_t)b.poolSize);
- b.labels = malloc((size_t)b.maxLabels * sizeof *b.labels);
- b.hash = malloc((size_t)b.hashSize * sizeof *b.hash);
- if (size > 2000000000u || !cmds || !b.pool || !b.labels || !b.hash) {
- fprintf(stderr, "out of memory\n");
- return 1;
- }
- if (!kon_scriptParse(&b, source)) {
- fprintf(stderr, "%s:%d: %s\n", input, b.errorLine, b.error);
+ if (konsc_write(source, size, prefix, name, split, &result, error, sizeof error) != 0) {
+ fprintf(stderr, "%s: %s\n", input, error);
+ free(source);
return 1;
}
-
- /* a label at the very end would point past the list, so the list gets an end of its own to land on */
- cmds[b.count].op = KON_OP_END;
- cmds[b.count].a = cmds[b.count].b = cmds[b.count].c = cmds[b.count].d = 0;
- cmds[b.count].text = NULL;
- rows = b.count + 1;
- qsort(b.labels, (size_t)b.labelCount, sizeof *b.labels, compareLabels);
-
- if (split) {
- int part, first;
-
- for (part = 0, first = 0; first < rows; part++, first += split) {
- char suffix[32];
- int last = first + split < rows ? first + split : rows;
-
- snprintf(suffix, sizeof suffix, "_%d.inc", part);
- f = create(prefix, suffix);
- if (!f) return 1;
- fprintf(f, "/* part %d of %s, rows %d to %d, included by %s.c */\n", part, name, first, last - 1, name);
- for (i = first; i < last; i++) putRow(f, &cmds[i]);
- if (fclose(f) != 0) return 1;
- }
- }
-
- f = create(prefix, ".c");
- if (!f) return 1;
- {
- const char *base = strrchr(prefix, '/');
-
- fprintf(f, "/* made by kons2c from %s, don't edit */\n\n", strrchr(input, '/') ? strrchr(input, '/') + 1 : input);
- fprintf(f, "#include \"%s.h\"\n\n#include <string.h>\n\n", base ? base + 1 : prefix);
- }
- fprintf(f, "const int %s_count = %d;\n\n", name, rows);
- fprintf(f, "const kon_cmd_t %s_cmds[%d] = {\n", name, rows);
- if (split) {
- const char *base = strrchr(prefix, '/');
- int part, first;
-
- for (part = 0, first = 0; first < rows; part++, first += split) fprintf(f, "#include \"%s_%d.inc\"\n", base ? base + 1 : prefix, part);
- } else {
- for (i = 0; i < rows; i++) putRow(f, &cmds[i]);
- }
- fprintf(f, "};\n\n");
- fprintf(f, "const int %s_labelCount = %d;\n\n", name, b.labelCount);
- fprintf(f, "const kon_scriptLabel_t %s_labels[%d] = {\n", name, b.labelCount > 0 ? b.labelCount : 1);
- for (i = 0; i < b.labelCount; i++) {
- fprintf(f, "\t{");
- putString(f, b.labels[i].name);
- fprintf(f, ", %d},\n", b.labels[i].at);
- }
- if (b.labelCount == 0) fprintf(f, "\t{\"\", 0}\n");
- fprintf(f, "};\n\n");
- fprintf(f, "int %s_find(const char *label)\n{\n\tint low = 0, high = %s_labelCount - 1;\n\n", name, name);
- fprintf(f, "\twhile (low <= high) {\n\t\tint mid = low + (high - low) / 2;\n\t\tint order = strcmp(label, %s_labels[mid].name);\n\n", name);
- fprintf(f, "\t\tif (order == 0) return %s_labels[mid].at;\n\t\tif (order < 0) high = mid - 1;\n\t\telse low = mid + 1;\n\t}\n\treturn -1;\n}\n", name);
- if (fclose(f) != 0) return 1;
-
- f = create(prefix, ".h");
- if (!f) return 1;
- fprintf(f, "/* made by kons2c, don't edit */\n\n#ifndef %s_H\n#define %s_H\n\n#include \"konscript.h\"\n\n", upper, upper);
- fprintf(f, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n");
- fprintf(f, "#define %s_COUNT %d\n\n", upper, rows);
- fprintf(f, "extern const int %s_count;\nextern const kon_cmd_t %s_cmds[%d];\n", name, name, rows);
- fprintf(f, "extern const int %s_labelCount;\nextern const kon_scriptLabel_t %s_labels[%d];\n\n", name, name, b.labelCount > 0 ? b.labelCount : 1);
- fprintf(f, "/* where a label is, or -1 */\nint %s_find(const char *label);\n\n", name);
- fprintf(f, "#ifdef __cplusplus\n}\n#endif\n#endif\n");
- if (fclose(f) != 0) return 1;
-
- printf("%s: %d commands, %d labels%s\n", name, rows, b.labelCount, split ? ", split" : "");
+ printf("%s: %d commands, %d labels%s\n", name, result.commands, result.labels, split ? ", split" : "");
free(source);
- free(cmds);
- free(b.pool);
- free(b.labels);
- free(b.hash);
return 0;
}