From: Michael Tremer Date: Tue, 23 Feb 2021 20:30:57 +0000 (+0000) Subject: parser: Parse multi-line definitions X-Git-Tag: 0.9.28~1285^2~712 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=15746df5d0546e57604f3b9575b6ffaeca09f4a4;p=pakfire.git parser: Parse multi-line definitions Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/parser/grammar.y b/src/libpakfire/parser/grammar.y index 74dd2da0f..cd6439ade 100644 --- a/src/libpakfire/parser/grammar.y +++ b/src/libpakfire/parser/grammar.y @@ -59,17 +59,25 @@ enum operator { %} +%token T_INDENT +%token T_OUTDENT + %token T_KEY %token T_STRING %token T_EOL +%token T_END + %token T_ASSIGN %token T_APPEND %type key %type value +%type lines +%type line + %union { PakfireParser parser; char* string; @@ -97,6 +105,12 @@ declaration : key T_ASSIGN value T_EOL 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 @@ -113,6 +127,20 @@ value : T_STRING } ; +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) { diff --git a/src/libpakfire/parser/scanner.l b/src/libpakfire/parser/scanner.l index 0177ce495..5b3c347f2 100644 --- a/src/libpakfire/parser/scanner.l +++ b/src/libpakfire/parser/scanner.l @@ -43,9 +43,18 @@ int num_lines; #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] @@ -66,11 +75,30 @@ key ({letter}|{underscore})(({letter}|{digit}|{underscore})*({letter}|{digi } \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); @@ -111,4 +139,60 @@ key ({letter}|{underscore})(({letter}|{digit}|{underscore})*({letter}|{digi return T_STRING; } +\t { + if (readline_indent && current_indent >= readline_indent) + REJECT; + + current_indent++; + } +\n { + // Jump back into indentation processing after a newline + current_indent = 0; + + return T_EOL; + } +. { + 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); + } + +\t { current_indent++; } +\n { current_indent = 0; } +. { + // 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(); + } + } + %% diff --git a/tests/libpakfire/parser.c b/tests/libpakfire/parser.c index 63516073e..f40c28dcf 100644 --- a/tests/libpakfire/parser.c +++ b/tests/libpakfire/parser.c @@ -106,7 +106,13 @@ static int test_parser(const struct test* t) { 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);