]> git.ipfire.org Git - pakfire.git/commitdiff
parser: Start from scratch
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 23 Feb 2021 19:39:51 +0000 (19:39 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 23 Feb 2021 19:39:51 +0000 (19:39 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/parser/grammar.y
src/libpakfire/parser/scanner.l
tests/libpakfire/parser.c

index 9f5981efae91bcbbb140bd2b035dcb9805a7d48b..160799ea5f54126b592e80d8c3e0a2ad4d213c7e 100644 (file)
@@ -18,8 +18,6 @@
 #                                                                             #
 #############################################################################*/
 
-%glr-parser
-
 %parse-param {PakfireParser parser}
 
 // Generate verbose error messages
@@ -38,7 +36,7 @@
 
 #define YYERROR_VERBOSE 1
 
-#define YYDEBUG 0
+#define YYDEBUG 1
 #if ENABLE_DEBUG && YYDEBUG
        int yydebug = 1;
 #endif
@@ -59,186 +57,55 @@ enum operator {
        OP_EQUALS = 0,
 };
 
-static PakfireParser make_if_stmt(PakfireParser parser, const enum operator op,
-       const char* val1, const char* val2, PakfireParser if_block, PakfireParser else_block);
+%}
 
-static PakfireParser make_child(PakfireParser parent, const char* namespace);
+%token <string>                                T_KEY
+%token <string>                                T_STRING
 
-%}
+%token                                         T_EOL
 
-%token                                                 T_APPEND
-%token                                                 T_ASSIGN
-%token                                                 T_DEFINE
-%token                                                 T_END
-%token                                                         T_EQUALS
-%token                                                 T_IF
-%token                                                 T_ELSE
-%token                                                 T_EOL
-%token <string>                                        T_WORD
-
-%type <string>                                 define;
-%type <string>                                 line;
-%type <string>                                 text;
-%type <string>                                 variable;
-%type <string>                                 value;
-%type <string>                                 word;
-%type <string>                                 words;
-
-%type <parser>                                 grammar;
-
-%type <parser>                                 if_stmt;
-%type <parser>                                 else_stmt;
+%token                                         T_ASSIGN
+
+%type <string>                         key
+%type <string>                         value
 
 %union {
        PakfireParser parser;
        char* string;
 }
 
-%%
-
-grammar                                                : grammar statements
-                                                       | statements
-                                                       {
-                                                               $$ = parser;
-                                                       }
-                                                       ;
+%start grammar
 
-statements                                     : statement
-                                                       | if_stmt
-                                                       | block
-                                                       | empty;
+%%
 
-empty                                          : T_EOL
+grammar                                                : declarations
                                                        ;
 
-variable                                       : T_WORD;
+declarations                           : declarations declaration
+                                                       | declaration;
 
-value                                          : words
-                                                       | %empty
+declaration                                    : key T_ASSIGN value T_EOL
                                                        {
-                                                               $$ = NULL;
-                                                       };
-
-word                                           : T_WORD;
-
-words                                          : word
-                                                       | words word
-                                                       {
-                                                               int r = asprintf(&$$, "%s %s", $1, $2);
-                                                               if (r < 0) {
-                                                                       Pakfire pakfire = pakfire_parser_get_pakfire(parser);
-                                                                       ERROR(pakfire, "Could not allocate memory");
-                                                                       pakfire_unref(pakfire);
-                                                                       ABORT;
-                                                               }
-                                                       };
-
-line                                           : words T_EOL
-                                                       {
-                                                               // Only forward words
-                                                               $$ = $1;
-                                                       }
-                                                       | T_EOL {
-                                                               $$ = "";
-                                                       };
-
-text                                           : text line
-                                                       {
-                                                               int r = asprintf(&$$, "%s\n%s", $1, $2);
-                                                               if (r < 0) {
-                                                                       Pakfire pakfire = pakfire_parser_get_pakfire(parser);
-                                                                       ERROR(pakfire, "Could not allocate memory");
-                                                                       pakfire_unref(pakfire);
+                                                               int r = pakfire_parser_set(parser, $1, $3);
+                                                               if (r)
                                                                        ABORT;
-                                                               }
                                                        }
-                                                       | line
                                                        ;
 
-if                                                     : T_IF
-                                                       {
-                                                               // Open a new block
-                                                               parser = make_child(parser, NULL);
-                                                       };
-
-else                                           : T_ELSE T_EOL
-                                                       {
-                                                               // Close the if block
-                                                               parser = pakfire_parser_get_parent(parser);
-
-                                                               // Open a new else block
-                                                               parser = make_child(parser, NULL);
-                                                       };
-
-end                                                    : T_END T_EOL;
-
-if_stmt                                                : if variable T_EQUALS variable T_EOL grammar else_stmt end
+key                                                    : T_KEY
                                                        {
-                                                               PakfireParser result = make_if_stmt(parser, OP_EQUALS, $2, $4, $6, $7);
+                                                               printf("KEY = %s\n", $1);
 
-                                                               // Close the whole if/else block
-                                                               parser = pakfire_parser_get_parent(parser);
-
-                                                               if (result)
-                                                                       pakfire_parser_merge(parser, result);
-
-                                                               pakfire_parser_unref($6);
-                                                               pakfire_parser_unref($7);
+                                                               $$ = $1;
                                                        }
                                                        ;
 
-else_stmt                                      : else grammar
-                                                       {
-                                                               $$ = $2;
-                                                       }
-                                                       | %empty
+value                                          : T_STRING
                                                        {
-                                                               $$ = NULL;
+                                                               $$ = $1;
                                                        }
                                                        ;
 
-block                                          : block_opening grammar end
-                                                       {
-                                                               // Move back to the parent parser
-                                                               parser = pakfire_parser_get_parent(parser);
-
-                                                               // Merge block into the parent parser
-                                                               pakfire_parser_merge(parser, $2);
-
-                                                               // Free block parser
-                                                               pakfire_parser_unref($2);
-                                                       };
-
-block_opening                          : variable T_EOL
-                                                       {
-                                                               // Create a new sub-parser which opens a new namespace
-                                                               parser = make_child(parser, $1);
-                                                       };
-
-statement                                      : variable T_ASSIGN value T_EOL
-                                                       {
-                                                               int r = pakfire_parser_set(parser, $1, $3);
-                                                               if (r < 0)
-                                                                       ABORT;
-                                                       }
-                                                       | variable T_APPEND value T_EOL
-                                                       {
-                                                               int r = pakfire_parser_append(parser, $1, $3);
-                                                               if (r < 0)
-                                                                       ABORT;
-                                                       }
-                                                       | define text end
-                                                       {
-                                                               int r = pakfire_parser_set(parser, $1, $2);
-                                                               if (r < 0)
-                                                                       ABORT;
-                                                       };
-
-define                                         : T_DEFINE variable T_EOL
-                                                       {
-                                                               $$ = $2;
-                                                       };
-
 %%
 
 int pakfire_parser_parse_data(PakfireParser parent, const char* data, size_t len) {
@@ -299,47 +166,3 @@ void yyerror(PakfireParser parser, const char* s) {
 
        pakfire_unref(pakfire);
 }
-
-static PakfireParser make_if_stmt(PakfireParser parser, const enum operator op,
-               const char* val1, const char* val2, PakfireParser if_block, PakfireParser else_block) {
-       Pakfire pakfire = pakfire_parser_get_pakfire(parser);
-
-       switch (op) {
-               case OP_EQUALS:
-                       DEBUG(pakfire, "Evaluating if statement: %s == %s?\n", val1, val2);
-                       break;
-       }
-
-       DEBUG(pakfire, "  parser = %p, if = %p, else = %p\n", parser, if_block, else_block);
-
-       // Expand values
-       char* v1 = pakfire_parser_expand(parser, val1);
-       char* v2 = pakfire_parser_expand(parser, val2);
-
-       PakfireParser result = NULL;
-
-       switch (op) {
-               case OP_EQUALS:
-                       DEBUG(pakfire, "  '%s' == '%s'?\n", v1, v2);
-
-                       if (strcmp(v1, v2) == 0)
-                               result = if_block;
-                       else
-                               result = else_block;
-
-                       break;
-       }
-
-       pakfire_unref(pakfire);
-       free(v1);
-       free(v2);
-
-       return result;
-}
-
-static PakfireParser make_child(PakfireParser parent, const char* namespace) {
-       PakfireParser parser = pakfire_parser_create_child(parent, namespace);
-       pakfire_parser_unref(parent);
-
-       return parser;
-}
index d6d973d4f434eb2a305eb2cd84dbcf8930cfb0c2..6c0e29f63860dde0312dfc82415028b361a9f8f2 100644 (file)
 #############################################################################*/
 
 %option noinput noyywrap yylineno
+%option nodefault
+%option stack noyy_top_state
+%option warn
+
+/* Do not let unput() trash yytext */
+%array
+
+/* %option verbose */
+%option debug
 
 %{
 #define YY_DECL int yylex()
 
 int num_lines;
 
+#include <assert.h>
+
 #include <ctype.h>
 #include <stdlib.h>
+
 #include <pakfire/parser.h>
-#include <pakfire/util.h>
+
 #include "grammar.h"
 
-static char* find_name(const char* s, const char* prefix) {
-       // Find the name of the package
-       const char* name = NULL;
-       for (unsigned int i = strlen(s); i > 0; i--) {
-               if (isspace(s[i]))
-                       break;
+%}
 
-               name = s + i;
-       }
+%x READLINE
 
-       // New length
-       size_t length = strlen(prefix) + strlen(name);
+letter                                 [A-Za-z]
+digit                                  [0-9]
+underscore                             _
+whitespace                             [ \t]+
 
-       // Allocate a new buffer and write the string into it
-       char* buffer = malloc(length + 1);
-       if (!buffer)
-               abort();
+key                                            ({letter}|{underscore})(({letter}|{digit}|{underscore})*({letter}|{digit}))?
 
-       snprintf(buffer, length + 1, "%s%s", prefix, name);
+%%
 
-       return buffer;
-}
-%}
+<*>\n                                  {
+                                                       // Handles line numbers without consuming the newline character
+                                                       num_lines++; REJECT;
+                                               }
 
-digit                  [0-9]
-letter                 [A-Za-z]
-underscore             _
-special                        [/\"'!@$%&*(){}+=:<>,;_\?\.\[\]\-\\\|]+
-whitespace             ([ \t])+
+#.*$                                   {
+                                                       /* ignore comments */
+                                               }
 
-quoted_string  \"([^\"])*\"
-word                   ({quoted_string}|({digit}|{letter}|{special})+)
+\n                                             {
+                                                       return T_EOL;
+                                               }
 
-/*
-       Compatibility for the old python parser.
+{whitespace}                   { /* consume any whitespace */ }
 
-       We automatically prepend "define" in front of some keywords, because
-       generally the language requires it.
-*/
-keywords               (description|{whitespace}(description|build(_cmds)?|files|filter_(provides|requires)|install(_cmds)?|prepare_cmds|provides|(pre)?requires|_posttrans))
-package                        {whitespace}package.*$
-script                 {whitespace}script.*$
+{key}                                  {
+                                                       // Copy the value
+                                                       yylval.string = strdup(yytext);
 
-/* Template definitions are indented once */
-template1              \ttemplate.*
+                                                       return T_KEY;
+                                               }
 
-/* In a package block, the template line is indented more than once */
-template2              {whitespace}template.*
+"="                                            {
+                                                       // Read everything after this
+                                                       yy_push_state(READLINE);
 
-%s DEFINE
+                                                       return T_ASSIGN;
+                                               }
 
-%%
+(.|\n)                                 {
+                                                       // Unexpected character
+                                                       fprintf(stderr, "Unexpected character: %s\n", yytext);
+                                                       abort();
+                                               }
+
+<READLINE>{whitespace} {
+                                                       // consume any leading whitespace
+                                               }
+<READLINE>.*$                  {
+                                                       // Return to caller
+                                                       yy_pop_state();
+
+                                                       // Copy the entire string
+                                                       yylval.string = strdup(yytext);
 
-#.*$                   { /* ignore comments */ }
-{whitespace}   {}
-\n                             { num_lines++; return T_EOL; }
-
-<INITIAL>^{package} {
-                                       char* buffer = find_name(yytext, "package:");
-
-                                       // Put the whole string back onto the stack (backwards)
-                                       for (int i = strlen(buffer) - 1; i >= 0; i--) {
-                                               unput(buffer[i]);
-                                       }
-
-                                       free(buffer);
-                               }
-
-<INITIAL>^{template1}$ {
-                                       char* buffer = find_name(yytext, "template:");
-
-                                       // Put the whole string back onto the stack (backwards)
-                                       for (int i = strlen(buffer) - 1; i >= 0; i--) {
-                                               unput(buffer[i]);
-                                       }
-
-                                       free(buffer);
-                               }
-
-<INITIAL>^{template2}$ {
-                                       char* buffer = find_name(yytext, "template = ");
-
-                                       // Put the whole string back onto the stack (backwards)
-                                       for (int i = strlen(buffer) - 1; i >= 0; i--) {
-                                               unput(buffer[i]);
-                                       }
-
-                                       free(buffer);
-                               }
-
-<INITIAL>^{script} {
-                                       char* buffer = find_name(yytext, "define script:");
-
-                                       // Put the whole string back onto the stack (backwards)
-                                       for (int i = strlen(buffer) - 1; i >= 0; i--) {
-                                               unput(buffer[i]);
-                                       }
-
-                                       free(buffer);
-                               }
-
-<INITIAL>^{keywords}$ {
-                                       // Determine the length of the string
-                                       size_t length = strlen("define ") + yyleng;
-
-                                       // Make a copy because unput touches yytext
-                                       char* buffer = malloc(length + 1);
-                                       if (!buffer)
-                                               abort();
-
-                                       snprintf(buffer, length + 1, "define %s", yytext);
-
-                                       // Put the whole string back onto the stack (backwards)
-                                       for (int i = length - 1; i >= 0; i--) {
-                                               unput(buffer[i]);
-                                       }
-
-                                       free(buffer);
-                               }
-
-<INITIAL>"=="  { return T_EQUALS; }
-<INITIAL>"="   { return T_ASSIGN; }
-<INITIAL>"+="  { return T_APPEND; }
-
-<INITIAL>"if"  { return T_IF; }
-<INITIAL>"else"        { return T_ELSE; }
-
-<INITIAL>"define" {
-                                       BEGIN(DEFINE);
-                                       return T_DEFINE;
-                               }
-<INITIAL>"def" {
-                                       BEGIN(DEFINE);
-                                       return T_DEFINE;
-                               }
-<INITIAL>"end" {
-                                       return T_END;
-                               }
-
-<DEFINE>"end"  {
-                                       BEGIN(0);
-                                       return T_END;
-                               }
-
-{quoted_string}        {
-                                       // Remove quotes
-                                       size_t len = strlen(yytext);
-                                       yytext[len-1] = '\0';
-
-                                       yylval.string = strdup(yytext + 1);
-                                       return T_WORD;
-                               }
-
-{word}                 {
-                                       yylval.string = strdup(yytext);
-                                       return T_WORD;
-                               }
+                                                       return T_STRING;
+                                               }
 
 %%
index 941cb41bcc1a7fe29b63b55792247fb8d572f787..5472537a40a7a10f520fcbb6041de66117b712c8 100644 (file)
@@ -103,8 +103,27 @@ static int test_parser(const struct test* t) {
        return EXIT_SUCCESS;
 }
 
+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}\n";
+
+       int r = pakfire_parser_parse(parser, INPUT, strlen(INPUT));
+       ASSERT(r == 0);
+
+       // Dump the parser
+       char* s = pakfire_parser_dump(parser);
+       printf("%s\n", s);
+       free(s);
+
+       pakfire_parser_unref(parser);
+
+       return EXIT_SUCCESS;
+}
+
 int main(int argc, char** argv) {
        testsuite_add_test(test_parser);
+       testsuite_add_test(test_parser_assign);
 
        return testsuite_run();
 }