mirror of
https://github.com/sigmasternchen/libparcival
synced 2025-03-15 11:58:53 +00:00
first working version
This commit is contained in:
parent
c2b97854d3
commit
5830bf0683
3 changed files with 168 additions and 15 deletions
147
src/main.c
147
src/main.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
23
src/parser.y
23
src/parser.y
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
Loading…
Reference in a new issue