From: Michael Tremer Date: Tue, 23 Feb 2021 19:39:51 +0000 (+0000) Subject: parser: Start from scratch X-Git-Tag: 0.9.28~1285^2~714 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f37774cd6000c8d9423fb8262e7669dd9cf7ce74;p=pakfire.git parser: Start from scratch Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/parser/grammar.y b/src/libpakfire/parser/grammar.y index 9f5981efa..160799ea5 100644 --- a/src/libpakfire/parser/grammar.y +++ b/src/libpakfire/parser/grammar.y @@ -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 T_KEY +%token 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 T_WORD - -%type define; -%type line; -%type text; -%type variable; -%type value; -%type word; -%type words; - -%type grammar; - -%type if_stmt; -%type else_stmt; +%token T_ASSIGN + +%type key +%type 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; -} diff --git a/src/libpakfire/parser/scanner.l b/src/libpakfire/parser/scanner.l index d6d973d4f..6c0e29f63 100644 --- a/src/libpakfire/parser/scanner.l +++ b/src/libpakfire/parser/scanner.l @@ -19,174 +19,89 @@ #############################################################################*/ %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 + #include #include + #include -#include + #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(); + } + +{whitespace} { + // consume any leading whitespace + } +.*$ { + // Return to caller + yy_pop_state(); + + // Copy the entire string + yylval.string = strdup(yytext); -#.*$ { /* ignore comments */ } -{whitespace} {} -\n { num_lines++; return T_EOL; } - -^{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); - } - -^{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); - } - -^{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); - } - -^{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); - } - -^{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); - } - -"==" { return T_EQUALS; } -"=" { return T_ASSIGN; } -"+=" { return T_APPEND; } - -"if" { return T_IF; } -"else" { return T_ELSE; } - -"define" { - BEGIN(DEFINE); - return T_DEFINE; - } -"def" { - BEGIN(DEFINE); - return T_DEFINE; - } -"end" { - return T_END; - } - -"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; + } %% diff --git a/tests/libpakfire/parser.c b/tests/libpakfire/parser.c index 941cb41bc..5472537a4 100644 --- a/tests/libpakfire/parser.c +++ b/tests/libpakfire/parser.c @@ -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(); }