%}
+%token T_INDENT
+%token T_OUTDENT
+
%token <string> T_KEY
%token <string> T_STRING
%token T_EOL
+%token T_END
+
%token T_ASSIGN
%token T_APPEND
%type <string> key
%type <string> value
+%type <string> lines
+%type <string> line
+
%union {
PakfireParser parser;
char* string;
if (r)
ABORT;
}
+ | key T_EOL T_INDENT lines T_OUTDENT T_END T_EOL
+ {
+ int r = pakfire_parser_set(parser, $1, $4);
+ if (r)
+ ABORT;
+ }
;
key : T_KEY
}
;
+lines : lines line
+ {
+ int r = asprintf(&$$, "%s\n%s", $1, $2);
+ if (r < 0)
+ ABORT;
+ }
+ | line;
+
+line : T_STRING T_EOL
+ {
+ $$ = $1;
+ }
+ ;
+
%%
int pakfire_parser_parse_data(PakfireParser parent, const char* data, size_t len) {
#include "grammar.h"
+// Indentation level
+unsigned int indent_level = 0;
+
+// Remember current indentation
+unsigned int current_indent = 0;
+unsigned int readline_indent = 0;
+
%}
+%x INDENT
%x READLINE
+%x READLINES
letter [A-Za-z]
digit [0-9]
}
\n {
+ // Jump back into indentation processing after a newline
+ current_indent = 0;
+
+ yy_push_state(INDENT);
+
return T_EOL;
}
{whitespace} { /* consume any whitespace */ }
+{key}$ {
+ // Hack to detect "end"
+ if (strcmp(yytext, "end") == 0)
+ return T_END;
+
+ // Copy the value
+ yylval.string = strdup(yytext);
+
+ // Enter into READLINES mode
+ yy_push_state(READLINES);
+
+ return T_KEY;
+ }
+
{key} {
// Copy the value
yylval.string = strdup(yytext);
return T_STRING;
}
+<READLINES>\t {
+ if (readline_indent && current_indent >= readline_indent)
+ REJECT;
+
+ current_indent++;
+ }
+<READLINES>\n {
+ // Jump back into indentation processing after a newline
+ current_indent = 0;
+
+ return T_EOL;
+ }
+<READLINES>. {
+ unput(*yytext);
+
+ if (!readline_indent) {
+ readline_indent = current_indent;
+ return T_INDENT;
+ }
+
+ // <-- ?
+ if (current_indent < readline_indent) {
+ readline_indent = 0;
+ yy_pop_state();
+ return T_OUTDENT;
+ }
+
+ yy_push_state(READLINE);
+ }
+
+<INDENT>\t { current_indent++; }
+<INDENT>\n { current_indent = 0; }
+<INDENT>. {
+ // Put the read character back for the next round
+ unput(*yytext);
+
+ // --> - More indentation?
+ if (current_indent > indent_level) {
+ indent_level++;
+ yy_pop_state();
+
+ return T_INDENT;
+
+ // <-- - If indentation has become less
+ } else if (current_indent < indent_level) {
+ indent_level--;
+ yy_pop_state();
+
+ return T_OUTDENT;
+
+ // If indentation has stayed the same
+ } else {
+ yy_pop_state();
+ }
+ }
+
%%
static int test_parser_assign(const struct test* t) {
PakfireParser parser = pakfire_parser_create(t->pakfire, NULL, NULL);
- static const char* INPUT = "a = 1\nb = 2\nc = %{a}%{b}\nd = A\nd += BC\n";
+ static const char* INPUT =
+ "a = 1\n"
+ "b = 2\n"
+ "c = %{a}%{b}\n"
+ "d = A\n"
+ "d += BC\n"
+ "lines\n\tline 1\n\tline 2\nend\n";
int r = pakfire_parser_parse(parser, INPUT, strlen(INPUT));
ASSERT(r == 0);