From e01841c1eb94d18e798b114978294a78be529f93 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Thu, 20 May 2021 19:42:42 +0200 Subject: [PATCH] now generating tree for template --- src/common.c | 24 +++++++++ src/common.h | 7 +++ src/parser.y | 90 +++++++++++++++++++++++++++++++-- src/scanner.l | 27 ++++++---- src/tree.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tree.h | 44 ++++++++++++++++ 6 files changed, 313 insertions(+), 16 deletions(-) create mode 100644 src/common.c create mode 100644 src/common.h create mode 100644 src/tree.c create mode 100644 src/tree.h diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..562efc9 --- /dev/null +++ b/src/common.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +#include "common.h" + + +void _panic(const char* function, const char* format, ...) { + fprintf(stderr, "panic: %s: ", function); + + va_list argptr; + va_start(argptr, format); + + vfprintf(stderr, format, argptr); + + va_end(argptr); + + if (errno != 0) { + fprintf(stderr, ": %s", strerror(errno)); + } + + fprintf(stderr, "\n"); +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..e076bbd --- /dev/null +++ b/src/common.h @@ -0,0 +1,7 @@ +#ifndef COMMON_H +#define COMMON_H + +void _panic(const char* f, const char* format, ...); +#define panic(...) _panic(__func__, __VA_ARGS__) + +#endif diff --git a/src/parser.y b/src/parser.y index 0ac7248..56fff85 100644 --- a/src/parser.y +++ b/src/parser.y @@ -1,13 +1,38 @@ %{ +#include +#include + +#include + int yylex(); extern void yyerror(char*); %} -%token SECTION TEXT COMMA END +%union { + struct tree tree; + struct params params; + + char* text; +} + +%type mainSection + +%type parameter +%type parameters +%type moreParameters + +%type statementHeader +%type blockStatement +%type statement +%type output +%type texts + +%token TEXT +%token SECTION COMMA END %token PARAMS_BEGIN PARAMS_END %token STATEMENT_BEGIN STATEMENT_END %token OUTPUT_BEGIN OUTPUT_END @@ -25,33 +50,88 @@ metaSection: /* empty */ ; parameters: /* empty */ + { + $$ = newParams(); + } | parameter moreParameters + { + $$ = combineParams($1, $2); + } ; -parameter: TEXT texts +parameter: TEXT TEXT + { + $$ = newParams(); + addParam(&$$, $1, $2); + } ; moreParameters: /* empty */ + { + $$ = newParams(); + } | COMMA parameter moreParameters + { + $$ = combineParams($2, $3); + } ; metaStatement: statement ; mainSection: /* empty */ - | TEXT mainSection - | STATEMENT_BEGIN blockStatement STATEMENT_END mainSection - | OUTPUT_BEGIN output OUTPUT_END mainSection + { + $$ = newTree(); + } + | mainSection TEXT + { + $$ = $1; + addNode(&$$, newTextNode($2)); + } + | mainSection statementHeader mainSection statementEnd + { + $$ = $1; + addNode(&$$, newStatementNode($2, $3)); + } + | mainSection OUTPUT_BEGIN output OUTPUT_END + { + $$ = $1; + addNode(&$$, newOutputNode($3)); + } +; + +statementHeader: STATEMENT_BEGIN blockStatement STATEMENT_END + { + $$ = $2; + } +; + +statementEnd: STATEMENT_BEGIN END STATEMENT_END ; blockStatement: statement + { + $$ = $1; + } ; statement: TEXT texts + { + $$ = combineStr($1, $2); + } ; output: TEXT texts + { + $$ = combineStr($1, $2); + } ; texts: /* empty */ + { + $$ = strdup(""); + } | TEXT texts + { + $$ = combineStr($1, $2); + } diff --git a/src/scanner.l b/src/scanner.l index 56121c4..221b1d8 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -3,7 +3,7 @@ whitespace [\n\t\r ] params_begin "{$" params_end "$}" -section "%%" +section "%%"[\t ]*\n statement_begin "{%" statement_end "%}" @@ -14,10 +14,12 @@ output_end "}}" block_end_token "end" block_end {whitespace}*{block_end_token}{whitespace}* +id [a-zA-Z_][a-zA-Z0-9_]* + type_prefixes "enum"|"struct" type_prefix {type_prefixes}{whitespace}+ type_pointer {whitespace}*"*" -type {type_prefix}?[a-zA-Z0-9_]+{type_pointer}? +type {type_prefix}?{id}{type_pointer}? %option noyywrap %option nounput @@ -37,6 +39,9 @@ type {type_prefix}?[a-zA-Z0-9_]+{type_pointer}? #include #include #include + #include + + #include #include "y.tab.h" @@ -50,25 +55,25 @@ type {type_prefix}?[a-zA-Z0-9_]+{type_pointer}? {whitespace}+ { /* ignore whitespaces */ } . { fprintf(stderr, "error: raw text not allowed in meta section (line %d)\n", yylineno); exit(1); } -{type} { return TEXT; } +{type} { yylval.text = strdup(yytext); return TEXT; } +{id} { yylval.text = strdup(yytext); return TEXT; } {params_end} { BEGIN(META_SECTION); return PARAMS_END; } "," { return COMMA; } {whitespace}+ { /* ignore whitespaces */ } -"$" { return TEXT; /* catch $ as text */ } . { fprintf(stderr, "error: illegal token '%s' in parameter block (line %d)\n", yytext, yylineno); exit(1); } -[^%e]+ { return TEXT; } +[^%e]+ { yylval.text = strdup(yytext); return TEXT; } {block_end} { return END; } -"%" { return TEXT; /* catch % as text */ } -"e" { return TEXT; /* catch e as text */ } +"%" { yylval.text = strdup(yytext); return TEXT; /* catch % as text */ } +"e" { yylval.text = strdup(yytext); return TEXT; /* catch e as text */ } {statement_end} { if (isMetaSection) BEGIN(META_SECTION); else BEGIN(MAIN_SECTION); return STATEMENT_END; } -{params_begin} { fprintf(stderr, "warning: parameter block not allowed in main section (line %d); assuming to be text\n", yylineno); return TEXT; } +{params_begin} { fprintf(stderr, "warning: parameter block not allowed in main section (line %d); assuming to be text\n", yylineno); yylval.text = strdup(yytext); return TEXT; } {statement_begin} { BEGIN(STATEMENT); return STATEMENT_BEGIN; } {output_begin} { BEGIN(OUTPUT); return OUTPUT_BEGIN; } -. { return TEXT; } +. { yylval.text = strdup(yytext); return TEXT; } -[^}]+ { return TEXT; } +[^}]+ { yylval.text = strdup(yytext); return TEXT; } {output_end} { BEGIN(MAIN_SECTION); return OUTPUT_END; } -"}" { return TEXT; /* catch } as text */ } +"}" { yylval.text = strdup(yytext); return TEXT; /* catch } as text */ } diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 0000000..2ed3449 --- /dev/null +++ b/src/tree.c @@ -0,0 +1,137 @@ +#include +#include + +#include "common.h" +#include "tree.h" + +char* combineStr(char* s1, char* s2) { + if (s1 == NULL || s2 == NULL) { + panic("argument is NULL"); + } + + char* s3 = malloc(strlen(s1) + strlen(s2) + 1); + strcpy(s3, s1); + strcat(s3, s2); + + free(s1); + free(s2); + + return s3; +} + +struct node newTextNode(char* text) { + return (struct node) { + .type = TEXT_NODE, + .value.text = text + }; +} + +struct node newStatementNode(char* stm, struct tree tree) { + + struct tree* _tree = malloc(sizeof(struct tree)); + if (_tree == NULL) { + panic("malloc"); + } + + memcpy(_tree, &tree, sizeof(struct tree)); + + return (struct node) { + .type = STATEMENT_NODE, + .statement = stm, + .value.tree = _tree + }; +} + +struct node newOutputNode(char* text) { + return (struct node) { + .type = OUTPUT_NODE, + .value.text = text + }; +} + +struct tree newTree() { + return (struct tree) { + .kids = NULL, + .kidsno = 0 + }; +} + +void addNode(struct tree* tree, struct node node) { + void* tmp = realloc(tree->kids, (sizeof (struct node)) * (tree->kidsno + 1)); + if (tmp == NULL) { + panic("realloc"); + } + + tree->kids = tmp; + tree->kids[tree->kidsno++] = node; +} + +struct tree combineTree(struct tree t1, struct tree t2) { + struct tree t = { + .kidsno = t1.kidsno + t2.kidsno + }; + + t.kids = malloc(sizeof(struct node) * t.kidsno); + if (t.kids == NULL) { + panic("malloc"); + } + + if (t1.kids != NULL) { + memcpy(t.kids, t1.kids, t1.kidsno * sizeof(struct node)); + free(t1.kids); + } + if (t2.kids != NULL) { + memcpy(t.kids + t1.kidsno, t2.kids, t2.kidsno * sizeof(struct node)); + free(t2.kids); + } + + return t; +} + +struct params newParams() { + return (struct params) { + .types = NULL, + .names = NULL, + .no = 0 + }; +} + +void addParam(struct params* params, char* type, char* name) { + void* tmp; + tmp = realloc(params->types, sizeof(char*) * (params->no + 1)); + if (tmp == NULL) { + panic("realloc"); + } + params->types = tmp; + tmp = realloc(params->names, sizeof(char*) * (params->no + 1)); + if (tmp == NULL) { + panic("realloc"); + } + params->names = tmp; + + params->types[params->no] = type; + params->names[params->no] = name; + params->no++; +} + +struct params combineParams(struct params p1, struct params p2) { + struct params p = { + .no = p1.no + p2.no + }; + + p.types = malloc(sizeof(char*) * p.no); + if (p.types == NULL) { + panic("malloc"); + } + p.names = malloc(sizeof(char*) * p.no); + if (p.names == NULL) { + panic("malloc"); + } + + memcpy(p.types, p1.types, p1.no * sizeof(char*)); + memcpy(p.types + p1.no, p2.types, p2.no * sizeof(char*)); + memcpy(p.names, p1.names, p1.no * sizeof(char*)); + memcpy(p.names + p1.no, p2.names, p2.no * sizeof(char*)); + + return p; +} diff --git a/src/tree.h b/src/tree.h new file mode 100644 index 0000000..2a0018e --- /dev/null +++ b/src/tree.h @@ -0,0 +1,44 @@ +#ifndef TREE_H_ +#define TREE_H_ + +char* combineStr(char*, char*); + +#define TEXT_NODE (0) +#define STATEMENT_NODE (1) +#define OUTPUT_NODE (2) + +struct node { + int type; + char* statement; + union { + struct tree* tree; + char* text; + } value; +}; + +struct tree { + struct node* kids; + size_t kidsno; +}; + + +struct node newTextNode(char*); +struct node newStatementNode(char*, struct tree); +struct node newOutputNode(char*); + +struct tree newTree(); +void addNode(struct tree*, struct node); +struct tree combineTree(struct tree, struct tree); + +struct params { + char** types; + char** names; + size_t no; +}; + +struct params newParams(); +void addParam(struct params*, char*, char*); +struct params combineParams(struct params, struct params); + + +#endif