diff options
author | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-04-17 23:49:55 -0300 |
---|---|---|
committer | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-04-17 23:49:55 -0300 |
commit | bf42a95568f5efffcc87a9b5a7683b7b270a098f (patch) | |
tree | 4d3ea13c85bc34b609271ce0bf3b35cdf5a98c6f /src | |
parent | da54782672331c68fc7c412f4ebe27a9738342eb (diff) | |
download | blogc-bf42a95568f5efffcc87a9b5a7683b7b270a098f.tar.gz blogc-bf42a95568f5efffcc87a9b5a7683b7b270a098f.tar.bz2 blogc-bf42a95568f5efffcc87a9b5a7683b7b270a098f.zip |
replaced leg-based parser with handmade parser for templates
yay! no leg parser needed anymore. parsers still needs some work and
error handling, though.
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/output.c | 2 | ||||
-rw-r--r-- | src/template-grammar.leg | 200 | ||||
-rw-r--r-- | src/template-parser.c | 296 | ||||
-rw-r--r-- | src/template-parser.h (renamed from src/template-grammar.h) | 9 |
5 files changed, 302 insertions, 213 deletions
@@ -13,19 +13,13 @@ #include <stdio.h> #include "source-parser.h" +#include "template-parser.h" #include <string.h> 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.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 <rafael@rafaelmartins.eng.br> -# -# This program can be distributed under the terms of the BSD License. -# See the file COPYING. -# - -%{ - -#include <stdio.h> -#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 <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file COPYING. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <stdbool.h> +#include <string.h> + +#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-grammar.h b/src/template-parser.h index 310acb5..1f43fe8 100644 --- a/src/template-grammar.h +++ b/src/template-parser.h @@ -6,14 +6,13 @@ * See the file COPYING. */ -#ifndef _TEMPLATE_GRAMMAR_H -#define _TEMPLATE_GRAMMAR_H +#ifndef _TEMPLATE_PARSER_H +#define _TEMPLATE_PARSER_H #include "utils/utils.h" typedef enum { - BLOGC_TEMPLATE_IF_STMT, - BLOGC_TEMPLATE_ELSE_STMT, + BLOGC_TEMPLATE_IF_STMT = 1, BLOGC_TEMPLATE_ENDIF_STMT, BLOGC_TEMPLATE_BLOCK_STMT, BLOGC_TEMPLATE_ENDBLOCK_STMT, @@ -26,7 +25,7 @@ typedef struct { char *value; } blogc_template_stmt_t; -b_slist_t* blogc_template_parse(const char *tmpl); +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 */ |