From bf42a95568f5efffcc87a9b5a7683b7b270a098f Mon Sep 17 00:00:00 2001 From: "Rafael G. Martins" Date: Fri, 17 Apr 2015 23:49:55 -0300 Subject: replaced leg-based parser with handmade parser for templates yay! no leg parser needed anymore. parsers still needs some work and error handling, though. --- src/main.c | 8 +- src/output.c | 2 +- src/template-grammar.h | 32 ----- src/template-grammar.leg | 200 -------------------------------- src/template-parser.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++ src/template-parser.h | 31 +++++ 6 files changed, 329 insertions(+), 240 deletions(-) delete mode 100644 src/template-grammar.h delete mode 100644 src/template-grammar.leg create mode 100644 src/template-parser.c create mode 100644 src/template-parser.h (limited to 'src') diff --git a/src/main.c b/src/main.c index d05c8d6..4e72b6e 100644 --- a/src/main.c +++ b/src/main.c @@ -13,19 +13,13 @@ #include #include "source-parser.h" +#include "template-parser.h" #include int main(int argc, char **argv) { - const char *a = - "\n \nBOLA : guda\n\t\n\n\n\n" - "CHUNDA: asd\n" - "----\n" - "{% block single_source %}\nbola\n\nzas\n"; - blogc_source_t *t = blogc_source_parse(a, strlen(a)); - printf("%s\n", t->content); printf("Hello, World!\n"); return 0; } diff --git a/src/output.c b/src/output.c index bd96b8e..1664afe 100644 --- a/src/output.c +++ b/src/output.c @@ -32,7 +32,7 @@ blogc_parser_syntax_error(const char *name, const char *src, size_t src_len, current++; } - fprintf(stderr, "%s parser error: syntax error near \"%s\"\n", name, + fprintf(stderr, "%s parser error: failed to parse input near \"%s\".\n", name, msg->str); b_string_free(msg, true); diff --git a/src/template-grammar.h b/src/template-grammar.h deleted file mode 100644 index 310acb5..0000000 --- a/src/template-grammar.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2015 Rafael G. Martins - * - * This program can be distributed under the terms of the BSD License. - * See the file COPYING. - */ - -#ifndef _TEMPLATE_GRAMMAR_H -#define _TEMPLATE_GRAMMAR_H - -#include "utils/utils.h" - -typedef enum { - BLOGC_TEMPLATE_IF_STMT, - BLOGC_TEMPLATE_ELSE_STMT, - BLOGC_TEMPLATE_ENDIF_STMT, - BLOGC_TEMPLATE_BLOCK_STMT, - BLOGC_TEMPLATE_ENDBLOCK_STMT, - BLOGC_TEMPLATE_VARIABLE_STMT, - BLOGC_TEMPLATE_CONTENT_STMT, -} blogc_template_stmt_type_t; - -typedef struct { - blogc_template_stmt_type_t type; - char *value; -} blogc_template_stmt_t; - -b_slist_t* blogc_template_parse(const char *tmpl); -void blogc_template_free_stmts(b_slist_t *stmts); - -#endif /* _TEMPLATE_GRAMMAR_H */ diff --git a/src/template-grammar.leg b/src/template-grammar.leg deleted file mode 100644 index 2425582..0000000 --- a/src/template-grammar.leg +++ /dev/null @@ -1,200 +0,0 @@ -# -# blogc: A blog compiler. -# Copyright (C) 2015 Rafael G. Martins -# -# This program can be distributed under the terms of the BSD License. -# See the file COPYING. -# - -%{ - -#include -#include "utils/utils.h" -#include "template-grammar.h" - -#define YY_INPUT(buf, result, max_size) \ -{ \ - int yyc = (charbuf && *charbuf != '\0') ? *charbuf++ : EOF; \ - result = (EOF == yyc) ? 0 : (*buf = yyc, 1); \ -} - - -static b_slist_t *stmts = NULL; -static int if_count = 0; -static int block_count = 0; -static const char *charbuf = NULL; - - -static void -blogc_template_if_stmt(const char *value) -{ - if (block_count <= 0) { - fprintf(stderr, "Syntax error: {" "%% if ... %%" "} statement before " - "any {" "%% block ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_IF_STMT; - stmts = b_slist_append(stmts, stmt); - if_count++; -} - - -static void -blogc_template_else_stmt(void) -{ - if (if_count <= 0) { - fprintf(stderr, "Syntax error: {" "%% else %%" "} statement without " - "any open {" "%% if ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = NULL; - stmt->type = BLOGC_TEMPLATE_ELSE_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_endif_stmt(void) -{ - if (if_count-- <= 0) { - fprintf(stderr, "Syntax error: {" "%% endif %%" "} statement before " - "any {" "%% if ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = NULL; - stmt->type = BLOGC_TEMPLATE_ENDIF_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_block_stmt(const char *value) -{ - if (block_count > 0) { - fprintf(stderr, "Syntax error: {" "%% block %%" "} statements " - "can't be nested\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_BLOCK_STMT; - stmts = b_slist_append(stmts, stmt); - block_count++; -} - - -static void -blogc_template_endblock_stmt(void) -{ - if (block_count-- <= 0) { - fprintf(stderr, "Syntax error: {" "%% endblock %%" "} statement before " - "any {" "%% block ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = NULL; - stmt->type = BLOGC_TEMPLATE_ENDBLOCK_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_variable_stmt(const char *value) -{ - if (block_count <= 0) { - fprintf(stderr, "Syntax error: {{ ... }} statement before " - "any {" "%% block ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_VARIABLE_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_content_stmt(const char *value) -{ - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_CONTENT_STMT; - stmts = b_slist_append(stmts, stmt); -} - -%} - -page = if | else | endif | block | endblock | print | content | anything - { fprintf(stderr, "Syntax error near: %s\n", yytext); exit(1); } - - -# Useful rules -eol = '\n' | '\r\n' | '\r' -eof = !. -- = [\t ]* -id = [A-Z][A-Z0-9_]* -anything = < ( !eol . )* > eol - -# Conditionals -if_open = '{%' - -if_close = - '%}' -if = if_open 'if' ' '+ < id > if_close { blogc_template_if_stmt(yytext); } -else = if_open 'else' if_close { blogc_template_else_stmt(); } -endif = if_open 'endif' if_close { blogc_template_endif_stmt(); } - -# Blocks -block_open = '{%' - -block_close = - '%}' -block_name = ( 'single_source' | 'multiple_sources_once' | 'multiple_sources' ) -block = block_open 'block' ' '+ < block_name > block_close { blogc_template_block_stmt(yytext); } -endblock = block_open 'endblock' block_close { blogc_template_endblock_stmt(); } - -# Print calls -print_open = '{{' - -print_close = - '}}' -print_var = < id > { blogc_template_variable_stmt(yytext); } -print = print_open print_var print_close - -# Generic content -content = < ( !eof !if_open !if_close !block_open !block_close !print_open !print_close . )+ > - { blogc_template_content_stmt(yytext); } - -%% - - -void -blogc_template_free_stmts(b_slist_t *stmts) -{ - for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) { - blogc_template_stmt_t *data = tmp->data; - free(data->value); - free(data); - } - b_slist_free(stmts); -} - - -b_slist_t* -blogc_template_parse(const char *tmpl) -{ - if_count = 0; - block_count = 0; - charbuf = tmpl; - while(yyparse()); - if (if_count != 0) { - fprintf(stderr, "Syntax error: You left %d open {" "%% if ... %%" "} statements.\n", if_count); - exit(1); - } - if (block_count != 0) { - fprintf(stderr, "Syntax error: You left %d open {" "%% block ... %%" "} statements.\n", block_count); - exit(1); - } - b_slist_t *rv = stmts; - charbuf = NULL; - stmts = NULL; - return rv; -} diff --git a/src/template-parser.c b/src/template-parser.c new file mode 100644 index 0000000..c5286ea --- /dev/null +++ b/src/template-parser.c @@ -0,0 +1,296 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file COPYING. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include "utils/utils.h" +#include "template-parser.h" +#include "output.h" + + +typedef enum { + TEMPLATE_START = 1, + TEMPLATE_OPEN_BRACKET, + TEMPLATE_BLOCK_START, + TEMPLATE_BLOCK_TYPE, + TEMPLATE_BLOCK_BLOCK_TYPE_START, + TEMPLATE_BLOCK_BLOCK_TYPE, + TEMPLATE_BLOCK_IF_VARIABLE_START, + TEMPLATE_BLOCK_IF_VARIABLE, + TEMPLATE_BLOCK_END, + TEMPLATE_VARIABLE_START, + TEMPLATE_VARIABLE, + TEMPLATE_VARIABLE_END, + TEMPLATE_CLOSE_BRACKET, +} blogc_template_parser_state_t; + + +b_slist_t* +blogc_template_parse(const char *src, size_t src_len) +{ + size_t current = 0; + size_t start = 0; + size_t end = 0; + size_t remaining = 0; + + bool error = false; + char *tmp = NULL; + + bool open_block = false; + unsigned int if_count = 0; + + b_slist_t *stmts = NULL; + blogc_template_stmt_t *stmt = NULL; + + blogc_template_parser_state_t state = TEMPLATE_START; + blogc_template_stmt_type_t type = BLOGC_TEMPLATE_CONTENT_STMT; + + while (current < src_len) { + char c = src[current]; + bool last = current == src_len - 1; + + switch (state) { + + case TEMPLATE_START: + if (last) { + stmt = malloc(sizeof(blogc_template_stmt_t)); + stmt->type = type; + stmt->value = b_strndup(src + start, src_len - start); + stmts = b_slist_append(stmts, stmt); + stmt = NULL; + } + if (c == '{') { + end = current; + state = TEMPLATE_OPEN_BRACKET; + } + break; + + case TEMPLATE_OPEN_BRACKET: + if (c == '%' || c == '{') { + if (c == '%') + state = TEMPLATE_BLOCK_START; + else + state = TEMPLATE_VARIABLE_START; + if (end > start) { + stmt = malloc(sizeof(blogc_template_stmt_t)); + stmt->type = type; + stmt->value = b_strndup(src + start, end - start); + stmts = b_slist_append(stmts, stmt); + stmt = NULL; + } + } + break; + + case TEMPLATE_BLOCK_START: + if (c == ' ') + break; + if (c >= 'a' && c <= 'z') { + state = TEMPLATE_BLOCK_TYPE; + start = current; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_TYPE: + if (c >= 'a' && c <= 'z') + break; + if (c == ' ') { + if (0 == strncmp("block", src + start, current - start)) { + if (!open_block) { + state = TEMPLATE_BLOCK_BLOCK_TYPE_START; + type = BLOGC_TEMPLATE_BLOCK_STMT; + start = current; + open_block = true; + break; + } + } + else if (0 == strncmp("endblock", src + start, current - start)) { + if (open_block) { + state = TEMPLATE_BLOCK_END; + type = BLOGC_TEMPLATE_ENDBLOCK_STMT; + open_block = false; + break; + } + } + else if (0 == strncmp("if", src + start, current - start)) { + if (open_block) { + state = TEMPLATE_BLOCK_IF_VARIABLE_START; + type = BLOGC_TEMPLATE_IF_STMT; + start = current; + if_count++; + break; + } + } + else if (0 == strncmp("endif", src + start, current - start)) { + if (open_block) { + if (if_count > 0) { + state = TEMPLATE_BLOCK_END; + type = BLOGC_TEMPLATE_ENDIF_STMT; + if_count--; + break; + } + } + } + } + error = true; + break; + + case TEMPLATE_BLOCK_BLOCK_TYPE_START: + if (c == ' ') + break; + if (c >= 'a' && c <= 'z') { + state = TEMPLATE_BLOCK_BLOCK_TYPE; + start = current; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_BLOCK_TYPE: + if ((c >= 'a' && c <= 'z') || c == '_') + break; + if (c == ' ') { + if ((0 == strncmp("single_source", src + start, current - start)) || + (0 == strncmp("multiple_sources", src + start, current - start)) || + (0 == strncmp("multiple_sources_once", src + start, current - start))) + { + end = current; + state = TEMPLATE_BLOCK_END; + break; + } + } + error = true; + break; + + case TEMPLATE_BLOCK_IF_VARIABLE_START: + if (c == ' ') + break; + if (c >= 'A' && c <= 'Z') { + state = TEMPLATE_BLOCK_IF_VARIABLE; + start = current; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_IF_VARIABLE: + if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') + break; + if (c == ' ') { + end = current; + state = TEMPLATE_BLOCK_END; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_END: + if (c == ' ') + break; + if (c == '%') { + state = TEMPLATE_CLOSE_BRACKET; + break; + } + error = true; + break; + + case TEMPLATE_VARIABLE_START: + if (c == ' ') + break; + if (c >= 'A' && c <= 'Z') { + if (open_block) { + state = TEMPLATE_VARIABLE; + type = BLOGC_TEMPLATE_VARIABLE_STMT; + start = current; + break; + } + } + error = true; + break; + + case TEMPLATE_VARIABLE: + if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') + break; + if (c == ' ') { + end = current; + state = TEMPLATE_VARIABLE_END; + break; + } + if (c == '}') { + end = current; + state = TEMPLATE_CLOSE_BRACKET; + break; + } + error = true; + break; + + case TEMPLATE_VARIABLE_END: + if (c == ' ') + break; + if (c == '}') { + state = TEMPLATE_CLOSE_BRACKET; + break; + } + error = true; + break; + + case TEMPLATE_CLOSE_BRACKET: + if (c == '}') { + stmt = malloc(sizeof(blogc_template_stmt_t)); + stmt->type = type; + stmt->value = NULL; + if (end > start) + stmt->value = b_strndup(src + start, end - start); + stmts = b_slist_append(stmts, stmt); + stmt = NULL; + state = TEMPLATE_START; + type = BLOGC_TEMPLATE_CONTENT_STMT; + start = current + 1; + break; + } + error = true; + break; + + } + + if (error) + break; + + current++; + } + + if (error) { + if (stmt != NULL) { + free(stmt->value); + free(stmt); + } + blogc_template_free_stmts(stmts); + blogc_parser_syntax_error("template", src, src_len, current); + return NULL; + } + + return stmts; +} + + +void +blogc_template_free_stmts(b_slist_t *stmts) +{ + for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) { + blogc_template_stmt_t *data = tmp->data; + free(data->value); + free(data); + } + b_slist_free(stmts); +} diff --git a/src/template-parser.h b/src/template-parser.h new file mode 100644 index 0000000..1f43fe8 --- /dev/null +++ b/src/template-parser.h @@ -0,0 +1,31 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file COPYING. + */ + +#ifndef _TEMPLATE_PARSER_H +#define _TEMPLATE_PARSER_H + +#include "utils/utils.h" + +typedef enum { + BLOGC_TEMPLATE_IF_STMT = 1, + BLOGC_TEMPLATE_ENDIF_STMT, + BLOGC_TEMPLATE_BLOCK_STMT, + BLOGC_TEMPLATE_ENDBLOCK_STMT, + BLOGC_TEMPLATE_VARIABLE_STMT, + BLOGC_TEMPLATE_CONTENT_STMT, +} blogc_template_stmt_type_t; + +typedef struct { + blogc_template_stmt_type_t type; + char *value; +} blogc_template_stmt_t; + +b_slist_t* blogc_template_parse(const char *src, size_t src_len); +void blogc_template_free_stmts(b_slist_t *stmts); + +#endif /* _TEMPLATE_GRAMMAR_H */ -- cgit v1.2.3-18-g5258