aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRafael G. Martins <rafael@rafaelmartins.eng.br>2015-04-17 23:49:55 -0300
committerRafael G. Martins <rafael@rafaelmartins.eng.br>2015-04-17 23:49:55 -0300
commitbf42a95568f5efffcc87a9b5a7683b7b270a098f (patch)
tree4d3ea13c85bc34b609271ce0bf3b35cdf5a98c6f /src
parentda54782672331c68fc7c412f4ebe27a9738342eb (diff)
downloadblogc-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.c8
-rw-r--r--src/output.c2
-rw-r--r--src/template-grammar.leg200
-rw-r--r--src/template-parser.c296
-rw-r--r--src/template-parser.h (renamed from src/template-grammar.h)9
5 files changed, 302 insertions, 213 deletions
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 <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 */