From 8001a0abc5f72c5055a76c566b8b6f04ba784b1c Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Sun, 22 Nov 2009 05:35:45 +0000 Subject: [PATCH] Add C/Bison/Lex ct parser --- .gitignore | 5 +++-- tmpl.awk => ct.awk | 0 ct.c | 40 +++++++++++++++++++++++++++++++++++++ example/html.ct | 16 +++++++-------- gallery/html.ct | 37 +++++++++++++++++----------------- mkcommon | 3 ++- mkfile | 11 +++++++++++ parse.y | 49 ++++++++++++++++++++++++++++++++++++++++++++++ scan.l | 23 ++++++++++++++++++++++ 9 files changed, 154 insertions(+), 30 deletions(-) rename tmpl.awk => ct.awk (100%) create mode 100644 ct.c create mode 100644 mkfile create mode 100644 parse.y create mode 100644 scan.l diff --git a/.gitignore b/.gitignore index b3f23b6..1a42267 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o *~ -lib.c -test +ct +parse.[ch] +scan.c diff --git a/tmpl.awk b/ct.awk similarity index 100% rename from tmpl.awk rename to ct.awk diff --git a/ct.c b/ct.c new file mode 100644 index 0000000..3506b8c --- /dev/null +++ b/ct.c @@ -0,0 +1,40 @@ +#include +#include + +#include "parse.h" + +gpointer parse(FILE *input, GList **data, GList **code); + +int main(int argc, char **argv) +{ + /* Parse arguments */ + int option_log_level = 7; + GOptionEntry entries[] = { + {"debug", 'd', 0, G_OPTION_ARG_INT, &option_log_level, + "Change default log level", "[1-7]"}, + {NULL} + }; + GOptionContext *context = g_option_context_new("infile"); + g_option_context_add_main_entries(context, entries, NULL); + g_option_context_parse(context, &argc, &argv, NULL); + + FILE *input = stdin; + for (int i = 1; i < argc; i++) + if (g_str_has_suffix(argv[i], ".ct")) + input = fopen(argv[i], "r"); + + /* Start compiling */ + GList *data = NULL; + GList *code = NULL; + parse(input, &data, &code); + data = g_list_reverse(data); + code = g_list_reverse(code); + + g_print("#include \n"); + g_print("\n"); + for (GList *cur = data; cur; cur = cur->next) + g_print("%s", cur->data); + g_print("\n"); + for (GList *cur = code; cur; cur = cur->next) + g_print("%s", cur->data); +} diff --git a/example/html.ct b/example/html.ct index e38344f..d08df11 100644 --- a/example/html.ct +++ b/example/html.ct @@ -1,16 +1,16 @@ -[void header() {] +<% void header() { %> Content-Type: application/xhtml+xml; charset=UTF-8 -[}] +<% } %> -[void body() {] - [for (int i = 0; i < 3; i++)] +<% void body() { %> + <% for (int i = 0; i < 3; i++) %>

hello, world

-[}] +<% } %> -[void html() {] +<% void html() { %> - [body();] + <% body(); %> -[}] +<% } %> diff --git a/gallery/html.ct b/gallery/html.ct index 4080fa3..e62621a 100644 --- a/gallery/html.ct +++ b/gallery/html.ct @@ -1,11 +1,12 @@ -[#include ] +<% #include %> -[void header() {] + +<% void header() { %> Content-Type: text/html; charset=UTF-8 -[}] +<% } %> -[void frame_index(){] +<% void frame_index(){ %> @@ -15,10 +16,10 @@ Content-Type: text/html; charset=UTF-8 -[}] +<% } %> -[void frame_head(){] +<% void frame_head(){ %> - [for (GList *cur = images; cur; cur = cur->next) {] + <% for (GList *cur = images; cur; cur = cur->next) { %> + <% gchar *img = (gchar *)cur->data; %> - [}] + <% } %> -[}] +<% } %> -[void frame_content(){] +<% void frame_content(){ %> -[}] +<% } %> diff --git a/mkcommon b/mkcommon index 4e2afaf..7ef68be 100644 --- a/mkcommon +++ b/mkcommon @@ -1,5 +1,6 @@ %.c: %.ct - ../tmpl.awk <$prereq >$target + (cd .. && mk) + ../ct <$prereq >$target ex +'norm gg=G' +'wq' $target <$HOME/lib/mkcommon diff --git a/mkfile b/mkfile new file mode 100644 index 0000000..8f43ffd --- /dev/null +++ b/mkfile @@ -0,0 +1,11 @@ +PROGS=ct +PKGS=glib-2.0 +ct-test:V: ct + ./ct < example/html.ct +ct: ct.o scan.o parse.o parse.h +%.c: %.l + flex -o $target $prereq +%.h %.c: %.y + bison -d -o $stem.c $stem.y +CLEAN=parse.h parse.c scan.c +<$HOME/lib/mkcommon diff --git a/parse.y b/parse.y new file mode 100644 index 0000000..11eb57c --- /dev/null +++ b/parse.y @@ -0,0 +1,49 @@ +%{ +#define YYSTYPE char * +#include +#include +extern FILE *yyin; +int yylex(void); +void yyerror(gpointer node, char const *s); +static GList *code = NULL; +static GList *data = NULL; +%} +%error-verbose +%parse-param {gpointer root}; +%token START END DATA OUT +%% + +input : all | all input ; + +all : data | code | print ; + +data : DATA { + static int i = 0; + data = g_list_prepend(data, g_strdup_printf( + "static char data%d[] = \"%s\\n\";\n", + i, g_strescape($1, ""))); + code = g_list_prepend(code, g_strdup_printf( + "fwrite(data%d, sizeof(data%d)-1, 1, stdout);\n", + i, i)); + i++; +}; + +code : START DATA END { + code = g_list_prepend(code, g_strdup_printf("%s\n", $2)); +}; + +print : START OUT DATA END { + code = g_list_prepend(code, g_strdup_printf("printf(%s);\n", $3)); +}; + +%% +gpointer parse(FILE *input, GList **_data, GList **_code) { + yyin = input; + yyparse(NULL); + *_data = data; + *_code = code; + return NULL; +} +void yyerror(gpointer root, char const *s) { + g_error("[%s]\n", s); +} diff --git a/scan.l b/scan.l new file mode 100644 index 0000000..19f6777 --- /dev/null +++ b/scan.l @@ -0,0 +1,23 @@ +%{ +#define YYSTYPE char * +#include +#include "parse.h" +#define debug(arg) // g_message("scan: " arg, yytext); +%} +%option noyywrap +%option nounput +%option noinput +/* %option nodebug */ +START [ \t]*<% +END [ \t]*%>[ \t]* +DATA ([^<\n]|<[^%])* +CODE [ \t\n]([^%\n]|%[^>])* +%s IN FMT +%% +{START} { debug("START [%s]"); yylval = g_strdup(yytext); BEGIN(IN); return START; } +{DATA} { debug("DATA [%s]"); yylval = g_strdup(yytext); return DATA; } +{END} { debug("END [%s]"); yylval = g_strdup(yytext); BEGIN(INITIAL); return END; } += { debug("OUT [%s]"); yylval = g_strdup(yytext); return OUT; } +{CODE} { debug("CODE [%s]"); yylval = g_strdup(yytext); return DATA; } +[\n] { debug("NL [%s]"); } +%% -- 2.43.2