diff options
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 */  | 
