mirror of
https://github.com/sigmasternchen/libparcival
synced 2025-03-15 11:58:53 +00:00
parent handling done
This commit is contained in:
parent
fdc425e0b3
commit
5623bdce6b
5 changed files with 142 additions and 50 deletions
52
src/main.c
52
src/main.c
|
@ -2,12 +2,14 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define PRINT_PREFIX ("print_template")
|
#define PRINT_PREFIX ("print_template")
|
||||||
#define SIZE_PREFIX ("size_template")
|
#define SIZE_PREFIX ("size_template")
|
||||||
|
#define END_SUFFIX ("end")
|
||||||
|
|
||||||
#define SIZE_ACCUMULATOR_VAR ("_total_size_")
|
#define SIZE_ACCUMULATOR_VAR ("_total_size_")
|
||||||
|
|
||||||
|
@ -21,14 +23,19 @@ FILE* output;
|
||||||
char* name;
|
char* name;
|
||||||
const char* filename;
|
const char* filename;
|
||||||
|
|
||||||
|
bool isAbstract = false;
|
||||||
|
|
||||||
void generateHeader() {
|
void generateHeader() {
|
||||||
fprintf(output, "#include <stdio.h>\n");
|
fprintf(output, "#include <stdio.h>\n");
|
||||||
fprintf(output, "#include <stdlib.h>\n");
|
fprintf(output, "#include <stdlib.h>\n");
|
||||||
fprintf(output, "#include <stdarg.h>\n");
|
fprintf(output, "#include <stdarg.h>\n");
|
||||||
|
fprintf(output, "#include <stdbool.h>\n");
|
||||||
fprintf(output, "\n");
|
fprintf(output, "\n");
|
||||||
fprintf(output, "#include <templates.h>\n");
|
fprintf(output, "#include <templates.h>\n");
|
||||||
fprintf(output, "\n");
|
fprintf(output, "\n");
|
||||||
fprintf(output, "extern void _registerTemplate(const char*, void (*)(FILE*, va_list), size_t (*)(va_list));\n");
|
fprintf(output, "extern void _registerTemplate(const char*, bool, void (*)(FILE*, va_list), void (*)(FILE*, va_list), size_t (*)(va_list));\n");
|
||||||
|
fprintf(output, "extern void renderTemplateStart(const char*, FILE*, ...);\n")
|
||||||
|
fprintf(output, "extern void renderTemplateEnd(const char*, FILE*, ...);\n")
|
||||||
fprintf(output, "\n");
|
fprintf(output, "\n");
|
||||||
fprintf(output, "#define _renderTemplate(f, t, ...) renderTemplate(t, f, __VA_ARGS__)\n");
|
fprintf(output, "#define _renderTemplate(f, t, ...) renderTemplate(t, f, __VA_ARGS__)\n");
|
||||||
fprintf(output, "\n");
|
fprintf(output, "\n");
|
||||||
|
@ -139,6 +146,9 @@ void parseTreeSize(int indentation, struct tree tree) {
|
||||||
case RENDER_NODE:
|
case RENDER_NODE:
|
||||||
generateRenderNodeSize(indentation, tree.kids[i]);
|
generateRenderNodeSize(indentation, tree.kids[i]);
|
||||||
break;
|
break;
|
||||||
|
case CHILD_NODE:
|
||||||
|
// ignore CHILD_NODE for size calculation
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
panic("unknown node type");
|
panic("unknown node type");
|
||||||
}
|
}
|
||||||
|
@ -185,6 +195,13 @@ void generateRenderNode(int indentation, struct node node) {
|
||||||
fprintf(output, "_renderTemplate(out, %s);\n", node.value.text);
|
fprintf(output, "_renderTemplate(out, %s);\n", node.value.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void generateChildNode() {
|
||||||
|
// assuming we are at root level in tree
|
||||||
|
fprintf(output, "}\n");
|
||||||
|
fprintf(output, "static void %s_%s_%s_(FILE* out, va_list argptr) {\n", PRINT_PREFIX, name, END_SUFFIX);
|
||||||
|
generateArguments();
|
||||||
|
}
|
||||||
|
|
||||||
void parseTree(int indentation, struct tree tree) {
|
void parseTree(int indentation, struct tree tree) {
|
||||||
for (size_t i = 0; i < tree.kidsno; i++) {
|
for (size_t i = 0; i < tree.kidsno; i++) {
|
||||||
switch(tree.kids[i].type) {
|
switch(tree.kids[i].type) {
|
||||||
|
@ -200,6 +217,9 @@ void parseTree(int indentation, struct tree tree) {
|
||||||
case RENDER_NODE:
|
case RENDER_NODE:
|
||||||
generateRenderNode(indentation, tree.kids[i]);
|
generateRenderNode(indentation, tree.kids[i]);
|
||||||
break;
|
break;
|
||||||
|
case CHILD_NODE:
|
||||||
|
generateChildNode();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
panic("unknown node type");
|
panic("unknown node type");
|
||||||
}
|
}
|
||||||
|
@ -217,7 +237,11 @@ void generateTree() {
|
||||||
|
|
||||||
void generateConstructor() {
|
void generateConstructor() {
|
||||||
fprintf(output, "__attribute__((constructor)) static void _register() {\n");
|
fprintf(output, "__attribute__((constructor)) static void _register() {\n");
|
||||||
fprintf(output, "\t_registerTemplate(\"%s\", &%s_%s_, &%s_%s_);\n", filename, PRINT_PREFIX, name, SIZE_PREFIX, name);
|
if (isAbstract) {
|
||||||
|
fprintf(output, "\t_registerTemplate(\"%s\", true, &%s_%s_, &%s_%s_%s_, &%s_%s_);\n", filename, PRINT_PREFIX, name, PRINT_PREFIX, name, END_SUFFIX, SIZE_PREFIX, name);
|
||||||
|
} else {
|
||||||
|
fprintf(output, "\t_registerTemplate(\"%s\", false, &%s_%s_, NULL, &%s_%s_);\n", filename, PRINT_PREFIX, name, SIZE_PREFIX, name);
|
||||||
|
}
|
||||||
fprintf(output, "}\n");
|
fprintf(output, "}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,6 +258,28 @@ void fixName() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void preprocessTree(int depth, struct tree tree);
|
||||||
|
|
||||||
|
void preprocessNode(int depth, struct node node) {
|
||||||
|
if (node.type == CHILD_NODE) {
|
||||||
|
if (depth > 0) {
|
||||||
|
panic("child command not allowed in statement block");
|
||||||
|
}
|
||||||
|
if (isAbstract) {
|
||||||
|
panic("only one child command allowed per template");
|
||||||
|
}
|
||||||
|
isAbstract = true;
|
||||||
|
} else if (node.type == STATEMENT_NODE) {
|
||||||
|
preprocessTree(depth + 1, *node.value.tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void preprocessTree(int depth, struct tree tree) {
|
||||||
|
for (size_t i = 0; i < tree.kidsno; i++) {
|
||||||
|
preprocessNode(depth, tree.kids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// TODO: build sane argument parsing
|
// TODO: build sane argument parsing
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
|
@ -257,6 +303,8 @@ int main(int argc, char** argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preprocessTree(0, result.tree);
|
||||||
|
|
||||||
generateHeader();
|
generateHeader();
|
||||||
generateSize();
|
generateSize();
|
||||||
generateTree();
|
generateTree();
|
||||||
|
|
|
@ -96,7 +96,11 @@ metaSection: /* empty */
|
||||||
yyerror("child command not allowed in meta section; ignoring");
|
yyerror("child command not allowed in meta section; ignoring");
|
||||||
break;
|
break;
|
||||||
case EXTENDS_TOKEN:
|
case EXTENDS_TOKEN:
|
||||||
yyerror("extends command not yet implemented; ignoring");
|
if ($$.parent != NULL) {
|
||||||
|
yyerror("template can only extent one parent");
|
||||||
|
YYERROR;
|
||||||
|
}
|
||||||
|
$$.parent = $6;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
yyerror("unhandled structure block command (internal error)");
|
yyerror("unhandled structure block command (internal error)");
|
||||||
|
@ -165,7 +169,7 @@ mainSection: /* empty */
|
||||||
addNode(&$$, newRenderNode($7));
|
addNode(&$$, newRenderNode($7));
|
||||||
break;
|
break;
|
||||||
case CHILD_NODE:
|
case CHILD_NODE:
|
||||||
yyerror("child command not yet implemented; ignoring");
|
addNode(&$$, newChildNode());
|
||||||
break;
|
break;
|
||||||
case EXTENDS_TOKEN:
|
case EXTENDS_TOKEN:
|
||||||
yyerror("extends command not allowed in main section; ignoring");
|
yyerror("extends command not allowed in main section; ignoring");
|
||||||
|
|
113
src/templates.c
113
src/templates.c
|
@ -2,6 +2,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -13,43 +14,39 @@ typedef size_t (*template_length_t)(va_list);
|
||||||
|
|
||||||
struct entry {
|
struct entry {
|
||||||
const char* name;
|
const char* name;
|
||||||
template_t f;
|
bool abstract;
|
||||||
|
template_t start;
|
||||||
|
template_t end;
|
||||||
template_length_t s;
|
template_length_t s;
|
||||||
} templates[MAX_TEMPLATES];
|
} templates[MAX_TEMPLATES];
|
||||||
size_t templateno = 0;
|
size_t templateno = 0;
|
||||||
|
|
||||||
static template_t _findTemplate(const char* name) {
|
static struct entry _findTemplate(const char* name) {
|
||||||
for (size_t i = 0; i < templateno; i++) {
|
for (size_t i = 0; i < templateno; i++) {
|
||||||
if (strcmp(templates[i].name, name) == 0) {
|
if (strcmp(templates[i].name, name) == 0) {
|
||||||
return templates[i].f;
|
return templates[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return (struct entry) {
|
||||||
|
.name = NULL
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static template_length_t _findTemplateSize(const char* name) {
|
void _registerTemplate(const char* name, bool abstract, template_t start, template_t end, template_length_t s) {
|
||||||
for (size_t i = 0; i < templateno; i++) {
|
|
||||||
if (strcmp(templates[i].name, name) == 0) {
|
|
||||||
return templates[i].s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _registerTemplate(const char* name, template_t f, template_length_t s) {
|
|
||||||
if (templateno >= MAX_TEMPLATES) {
|
if (templateno >= MAX_TEMPLATES) {
|
||||||
panic("max number of templates exceeded");
|
panic("max number of templates exceeded");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_findTemplate(name) != NULL) {
|
if (_findTemplate(name).name != NULL) {
|
||||||
fprintf(stderr, "warning: template name '%s' already registered; ignoring this one\n", name);
|
fprintf(stderr, "warning: template name '%s' already registered; ignoring this one\n", name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
templates[templateno].abstract = abstract;
|
||||||
templates[templateno].name = name;
|
templates[templateno].name = name;
|
||||||
templates[templateno].f = f;
|
templates[templateno].start = start;
|
||||||
|
templates[templateno].end = end;
|
||||||
templates[templateno++].s = s;
|
templates[templateno++].s = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,14 +54,49 @@ void _registerTemplate(const char* name, template_t f, template_length_t s) {
|
||||||
static size_t emptyTemplateSize(va_list _) { return 0; }
|
static size_t emptyTemplateSize(va_list _) { return 0; }
|
||||||
static void emptyTemplate(FILE* out, va_list _) { }
|
static void emptyTemplate(FILE* out, va_list _) { }
|
||||||
|
|
||||||
void _renderTemplate(const char* name, FILE* out, va_list argptr) {
|
template_t findTemplate(bool abstract, bool start, const char* name) {
|
||||||
template_t t = _findTemplate(name);
|
struct entry t = _findTemplate(name);
|
||||||
|
if (t.name == NULL) {
|
||||||
if (t == NULL) {
|
|
||||||
fprintf(stderr, "warning: template '%s' does not exist.\n", name);
|
fprintf(stderr, "warning: template '%s' does not exist.\n", name);
|
||||||
t = &emptyTemplate;
|
return &emptyTemplate;
|
||||||
}
|
}
|
||||||
|
if (t.abstract) {
|
||||||
|
if (!abstract) {
|
||||||
|
fprintf(stderr, "warning: template name '%s' is abstract\n", name);
|
||||||
|
return &emptyTemplate;
|
||||||
|
} else {
|
||||||
|
if (start) {
|
||||||
|
return t.start;
|
||||||
|
} else {
|
||||||
|
return t.end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return t.start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static template_length_t findTemplateSize(const char* name) {
|
||||||
|
struct entry t = _findTemplate(name);
|
||||||
|
if (t.name == NULL) {
|
||||||
|
fprintf(stderr, "warning: template '%s' does not exist.\n", name);
|
||||||
|
return &emptyTemplateSize;
|
||||||
|
}
|
||||||
|
return t.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _renderTemplate(const char* name, FILE* out, va_list argptr) {
|
||||||
|
template_t t = findTemplate(false, false, name);
|
||||||
|
t(out, argptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _renderTemplateStart(const char* name, FILE* out, va_list argptr) {
|
||||||
|
template_t t = findTemplate(true, true, name);
|
||||||
|
t(out, argptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _renderTemplateEnd(const char* name, FILE* out, va_list argptr) {
|
||||||
|
template_t t = findTemplate(true, false, name);
|
||||||
t(out, argptr);
|
t(out, argptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,14 +109,26 @@ void renderTemplate(const char* name, FILE* out, ...) {
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _sizeTemplate(const char* name, va_list argptr) {
|
void renderTemplateStart(const char* name, FILE* out, ...) {
|
||||||
template_length_t s = _findTemplateSize(name);
|
va_list argptr;
|
||||||
|
va_start(argptr, out);
|
||||||
|
|
||||||
if (s == NULL) {
|
_renderTemplateStart(name, out, argptr);
|
||||||
fprintf(stderr, "warning: template '%s' does not exist.\n", name);
|
|
||||||
s = &emptyTemplateSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
va_end(argptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderTemplateEnd(const char* name, FILE* out, ...) {
|
||||||
|
va_list argptr;
|
||||||
|
va_start(argptr, out);
|
||||||
|
|
||||||
|
_renderTemplateEnd(name, out, argptr);
|
||||||
|
|
||||||
|
va_end(argptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _sizeTemplate(const char* name, va_list argptr) {
|
||||||
|
template_length_t s = findTemplateSize(name);
|
||||||
return s(argptr);
|
return s(argptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +146,8 @@ size_t sizeTemplate(const char* name, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char* renderTemplateStr(const char* name, ...) {
|
char* renderTemplateStr(const char* name, ...) {
|
||||||
template_t t = _findTemplate(name);
|
template_t t = findTemplate(false, false, name);
|
||||||
template_length_t s = _findTemplateSize(name);
|
template_length_t s = findTemplateSize(name);
|
||||||
|
|
||||||
if (t == NULL) {
|
|
||||||
fprintf(stderr, "warning: template '%s' does not exist.\n", name);
|
|
||||||
t = &emptyTemplate;
|
|
||||||
s = &emptyTemplateSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t length;
|
size_t length;
|
||||||
char* result;
|
char* result;
|
||||||
|
@ -119,7 +157,6 @@ char* renderTemplateStr(const char* name, ...) {
|
||||||
va_copy(argptr2, argptr);
|
va_copy(argptr2, argptr);
|
||||||
|
|
||||||
length = s(argptr);
|
length = s(argptr);
|
||||||
|
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
|
|
||||||
result = malloc(length + 1);
|
result = malloc(length + 1);
|
||||||
|
|
16
src/tree.c
16
src/tree.c
|
@ -58,6 +58,12 @@ struct node newRenderNode(char* arguments) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct node newChildNode() {
|
||||||
|
return (struct node) {
|
||||||
|
.type = CHILD_NODE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
struct tree newTree() {
|
struct tree newTree() {
|
||||||
return (struct tree) {
|
return (struct tree) {
|
||||||
.kids = NULL,
|
.kids = NULL,
|
||||||
|
@ -148,8 +154,7 @@ struct params combineParams(struct params p1, struct params p2) {
|
||||||
struct stats newStats() {
|
struct stats newStats() {
|
||||||
return (struct stats) {
|
return (struct stats) {
|
||||||
.texts = NULL,
|
.texts = NULL,
|
||||||
.no = 0,
|
.no = 0
|
||||||
.parent = NULL
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,15 +169,12 @@ void addStat(struct stats* stats, char* text) {
|
||||||
stats->texts[stats->no++] = text;
|
stats->texts[stats->no++] = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setParent(struct stats* stats, char* parent) {
|
|
||||||
stats->parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct template newTemplate() {
|
struct template newTemplate() {
|
||||||
return (struct template) {
|
return (struct template) {
|
||||||
.params = newParams(),
|
.params = newParams(),
|
||||||
.stats = newStats(),
|
.stats = newStats(),
|
||||||
.tree = newTree()
|
.tree = newTree(),
|
||||||
|
.parent = NULL
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct node newTextNode(char*);
|
||||||
struct node newStatementNode(char*, struct tree);
|
struct node newStatementNode(char*, struct tree);
|
||||||
struct node newOutputNode(char*);
|
struct node newOutputNode(char*);
|
||||||
struct node newRenderNode(char*);
|
struct node newRenderNode(char*);
|
||||||
|
struct node newChildNode();
|
||||||
|
|
||||||
struct tree newTree();
|
struct tree newTree();
|
||||||
void addNode(struct tree*, struct node);
|
void addNode(struct tree*, struct node);
|
||||||
|
@ -49,7 +50,6 @@ struct params combineParams(struct params, struct params);
|
||||||
struct stats {
|
struct stats {
|
||||||
char** texts;
|
char** texts;
|
||||||
size_t no;
|
size_t no;
|
||||||
char* parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stats newStats();
|
struct stats newStats();
|
||||||
|
@ -59,6 +59,7 @@ struct template {
|
||||||
struct params params;
|
struct params params;
|
||||||
struct tree tree;
|
struct tree tree;
|
||||||
struct stats stats;
|
struct stats stats;
|
||||||
|
const char* parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct template newTemplate();
|
struct template newTemplate();
|
||||||
|
|
Loading…
Reference in a new issue