first working version

This commit is contained in:
overflowerror 2021-05-20 21:36:37 +02:00
parent c2b97854d3
commit 5830bf0683
3 changed files with 168 additions and 15 deletions

View file

@ -1,13 +1,154 @@
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tree.h"
#include "common.h"
extern int yyparse(); extern int yyparse();
extern int yylineno;
struct template result;
FILE* output;
const char* name;
void generateHeader() {
fprintf(output, "#include <stdio.h>\n");
fprintf(output, "#include <stdarg.h>\n");
fprintf(output, "\n");
for (size_t i = 0; i < result.stats.no; i++) {
fprintf(output, "%s\n", result.stats.texts[i]);
}
fprintf(output, "\n");
fprintf(output, "void _template_%s_(FILE* out, ...) {\n", name);
for (size_t i = 0; i < result.params.no; i++) {
fprintf(output, "\t%s %s;\n", result.params.types[i], result.params.names[i]);
}
fprintf(output, "\t{\n");
fprintf(output, "\t\tva_list argptr;\n");
fprintf(output, "\t\tva_start(argptr, out);\n");
for (size_t i = 0; i < result.params.no; i++) {
fprintf(output, "\t\t%s = va_arg(argptr, %s);\n", result.params.names[i], result.params.types[i]);
}
fprintf(output, "\t\tva_end(argptr);\n");
fprintf(output, "\t}\n");
}
char* fixText(char* text) {
size_t textLength = strlen(text);
size_t controlChars = 0;
for (size_t i = 0; i < textLength; i++) {
if (text[i] == '\t' || text[i] == '\n') {
controlChars++;
}
if (text[i] == '\\') {
controlChars++;
}
if (text[i] == '"') {
controlChars++;
}
}
char* tmp = malloc(textLength + controlChars + 1);
if (tmp == NULL) {
panic("malloc");
}
size_t i, j;
for (i = 0, j = 0; i < textLength; i++, j++) {
if (text[i] == '\t') {
tmp[j++] = '\\';
tmp[j] = 't';
} else if (text[i] == '\n') {
tmp[j++] = '\\';
tmp[j] = 'n';
} else if (text[i] == '\\' || text[i] == '"') {
tmp[j++] = '\\';
tmp[j] = text[i];
} else {
tmp[j] = text[i];
}
}
tmp[j] = '\0';
return tmp;
}
void indent(int indentation) {
for (int i = 0; i < indentation; i++) {
putc('\t', output);
}
}
static void parseTree(int, struct tree);
void generateTextNode(int indentation, struct node node) {
indent(indentation);
char* tmp = fixText(node.value.text);
fprintf(output, "fputs(\"%s\", out);\n", tmp);
free(tmp);
}
void generateStatementNode(int indentation, struct node node) {
indent(indentation);
fprintf(output, "%s {\n", node.statement);
parseTree(indentation + 1, *node.value.tree);
indent(indentation);
fprintf(output, "}\n");
}
void generateOutputNode(int indentation, struct node node) {
indent(indentation);
fprintf(output, "fprintf(out, %s);\n", node.value.text);
}
void parseTree(int indentation, struct tree tree) {
for (size_t i = 0; i < tree.kidsno; i++) {
switch(tree.kids[i].type) {
case TEXT_NODE:
generateTextNode(indentation, tree.kids[i]);
break;
case STATEMENT_NODE:
generateStatementNode(indentation, tree.kids[i]);
break;
case OUTPUT_NODE:
generateOutputNode(indentation, tree.kids[i]);
break;
default:
panic("unknown node type");
}
}
}
void generateTree() {
parseTree(1, result.tree);
}
void generateFooter() {
fprintf(output, "}\n");
}
int main() { int main() {
return yyparse(); output = stdout;
name = "test";
if (yyparse() < 0) {
return 1;
}
generateHeader();
generateTree();
generateFooter();
} }
void yyerror(char* s) { void yyerror(char* s) {
extern int yylineno;
fprintf(stderr, "%s (line %d)\n", s, yylineno); fprintf(stderr, "%s (line %d)\n", s, yylineno);
exit(1);
} }

View file

@ -10,6 +10,8 @@ int yylex();
extern void yyerror(char*); extern void yyerror(char*);
extern struct template result;
%} %}
%union { %union {
@ -20,7 +22,6 @@ extern void yyerror(char*);
char* text; char* text;
} }
%type <template> template
%type <template> metaSection %type <template> metaSection
%type <tree> mainSection %type <tree> mainSection
@ -35,6 +36,7 @@ extern void yyerror(char*);
%type <text> statement %type <text> statement
%type <text> output %type <text> output
%type <text> texts %type <text> texts
%type <text> text
%token <text> TEXT %token <text> TEXT
%token SECTION COMMA END %token SECTION COMMA END
@ -48,8 +50,8 @@ extern void yyerror(char*);
template: metaSection SECTION mainSection template: metaSection SECTION mainSection
{ {
$$ = $1; result = $1;
$$.tree = $3; result.tree = $3;
} }
/* | mainSection /* | mainSection
{ {
@ -116,7 +118,7 @@ mainSection: /* empty */
{ {
$$ = newTree(); $$ = newTree();
} }
| mainSection TEXT | mainSection text
{ {
$$ = $1; $$ = $1;
addNode(&$$, newTextNode($2)); addNode(&$$, newTextNode($2));
@ -160,11 +162,20 @@ output: TEXT texts
} }
; ;
text: TEXT
{
$$ = $1;
}
| TEXT text
{
$$ = combineStr($1, $2);
}
texts: /* empty */ texts: /* empty */
{ {
$$ = strdup(""); $$ = strdup("");
} }
| TEXT texts | text
{ {
$$ = combineStr($1, $2); $$ = $1;
} }

View file

@ -5,8 +5,8 @@ params_end "$}"
section "%%"[\t ]*\n section "%%"[\t ]*\n
statement_begin "{%" statement_begin [ \t]*"{%"
statement_end "%}" statement_end "%}"[ \t]*"\n"?
output_begin "{{" output_begin "{{"
output_end "}}" output_end "}}"
@ -19,7 +19,7 @@ id [a-zA-Z_][a-zA-Z0-9_]*
type_prefixes "enum"|"struct" type_prefixes "enum"|"struct"
type_prefix {type_prefixes}{whitespace}+ type_prefix {type_prefixes}{whitespace}+
type_pointer {whitespace}*"*" type_pointer {whitespace}*"*"
type_or_id {type_prefix}?{id}{type_pointer}? type_or_id {type_prefix}?{id}{type_pointer}*
%option noyywrap %option noyywrap
%option nounput %option nounput
@ -33,8 +33,6 @@ type_or_id {type_prefix}?{id}{type_pointer}?
%x STATEMENT %x STATEMENT
%x OUTPUT %x OUTPUT
%%
%{ %{
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
@ -48,6 +46,8 @@ type_or_id {type_prefix}?{id}{type_pointer}?
bool isMetaSection = true; bool isMetaSection = true;
%} %}
%%
<INITIAL,META_SECTION>{params_begin} { BEGIN(PARAMS); return PARAMS_BEGIN; } <INITIAL,META_SECTION>{params_begin} { BEGIN(PARAMS); return PARAMS_BEGIN; }
<INITIAL,META_SECTION>{statement_begin} { BEGIN(STATEMENT); return STATEMENT_BEGIN; } <INITIAL,META_SECTION>{statement_begin} { BEGIN(STATEMENT); return STATEMENT_BEGIN; }
<INITIAL,META_SECTION>{section} { isMetaSection = false; BEGIN(MAIN_SECTION); return SECTION; } <INITIAL,META_SECTION>{section} { isMetaSection = false; BEGIN(MAIN_SECTION); return SECTION; }
@ -65,11 +65,12 @@ type_or_id {type_prefix}?{id}{type_pointer}?
<STATEMENT>{block_end} { return END; } <STATEMENT>{block_end} { return END; }
<STATEMENT>"%" { yylval.text = strdup(yytext); return TEXT; /* catch % as text */ } <STATEMENT>"%" { yylval.text = strdup(yytext); return TEXT; /* catch % as text */ }
<STATEMENT>"e" { yylval.text = strdup(yytext); return TEXT; /* catch e as text */ } <STATEMENT>"e" { yylval.text = strdup(yytext); return TEXT; /* catch e as text */ }
<STATEMENT>{statement_end} { if (isMetaSection) BEGIN(META_SECTION); else BEGIN(MAIN_SECTION); return STATEMENT_END; } <STATEMENT>{statement_end} { BEGIN(isMetaSection ? META_SECTION : MAIN_SECTION); return STATEMENT_END; }
<MAIN_SECTION>{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; } <MAIN_SECTION>{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; }
<MAIN_SECTION>{statement_begin} { BEGIN(STATEMENT); return STATEMENT_BEGIN; } <MAIN_SECTION>{statement_begin} { BEGIN(STATEMENT); return STATEMENT_BEGIN; }
<MAIN_SECTION>{output_begin} { BEGIN(OUTPUT); return OUTPUT_BEGIN; } <MAIN_SECTION>{output_begin} { BEGIN(OUTPUT); return OUTPUT_BEGIN; }
<MAIN_SECTION>\n { yylval.text = strdup(yytext); return TEXT; }
<MAIN_SECTION>. { yylval.text = strdup(yytext); return TEXT; } <MAIN_SECTION>. { yylval.text = strdup(yytext); return TEXT; }
<OUTPUT>[^}]+ { yylval.text = strdup(yytext); return TEXT; } <OUTPUT>[^}]+ { yylval.text = strdup(yytext); return TEXT; }