X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fgrub2%2Fparser.y;h=81856dfcaa5a2002fce07a78460a6e1ddb0015d6;hp=a8c02e284b6d7b4507003839e1d5eb483814617f;hb=d39ae394911f945cd4a7789a8b210a5662852c46;hpb=ce2275ed4fa099035af123c25a1a7657f1ea6e78 diff --git a/discover/grub2/parser.y b/discover/grub2/parser.y index a8c02e2..81856df 100644 --- a/discover/grub2/parser.y +++ b/discover/grub2/parser.y @@ -2,8 +2,11 @@ %pure-parser %lex-param { yyscan_t scanner } %parse-param { struct grub2_parser *parser } +%error-verbose %{ +#include + #include "grub2.h" #include "parser.h" #include "lexer.h" @@ -27,6 +30,7 @@ static void yyerror(struct grub2_parser *, char const *s); %token TOKEN_DO "do" %token TOKEN_DONE "done" %token TOKEN_ELIF "elif" +%token TOKEN_ELSE "else" %token TOKEN_ESAC "esac" %token TOKEN_FI "fi" %token TOKEN_FOR "for" @@ -35,6 +39,7 @@ static void yyerror(struct grub2_parser *, char const *s); %token TOKEN_IN "in" %token TOKEN_MENUENTRY "menuentry" %token TOKEN_SELECT "select" +%token TOKEN_SUBMENU "submenu" %token TOKEN_THEN "then" %token TOKEN_TIME "time" %token TOKEN_UTIL "until" @@ -42,6 +47,9 @@ static void yyerror(struct grub2_parser *, char const *s); %type statement %type statements +%type conditional +%type elif +%type elifs %type words %type word @@ -55,36 +63,66 @@ static void yyerror(struct grub2_parser *, char const *s); %% -script: statements { - parser->statements = $1; +script: statements { + parser->script->statements = $1; } -statements: statement { +statements: /* empty */ { $$ = create_statements(parser); - statement_append($$, $1); } - | statements statement { + | statements statement TOKEN_EOL { statement_append($1, $2); + $$ = $1; + } + | statements TOKEN_EOL { + $$ = $1; } -statement: TOKEN_EOL { - $$ = NULL; +conditional: statement TOKEN_EOL "then" TOKEN_EOL statements { + $$ = create_statement_conditional(parser, $1, $5); + } + +elif: "elif" TOKEN_DELIM conditional { + $$ = $3; + } + +elifs: /* empty */ { + $$ = create_statements(parser); + } + | elifs elif { + statement_append($1, $2); + $$ = $1; } - | words TOKEN_EOL { + +statement: + words { $$ = create_statement_simple(parser, $1); } - | '{' statements '}' { $$ = NULL; } - | "if" TOKEN_DELIM statement - "then" TOKEN_EOL + | '{' statements '}' { + $$ = create_statement_block(parser, $2); + } + | "if" TOKEN_DELIM conditional elifs "fi" { + $$ = create_statement_if(parser, $3, $4, NULL); + } + | "if" TOKEN_DELIM conditional + elifs + "else" TOKEN_EOL statements - "fi" TOKEN_EOL { - $$ = create_statement_if(parser, $3, $6, NULL); + "fi" { + $$ = create_statement_if(parser, $3, $4, $7); + } + | "function" TOKEN_DELIM word TOKEN_DELIM '{' statements '}' { + $$ = create_statement_function(parser, $3, $6); } | "menuentry" TOKEN_DELIM words TOKEN_DELIM - '{' statements '}' - TOKEN_EOL { + '{' statements '}' { $$ = create_statement_menuentry(parser, $3, $6); } + | "submenu" TOKEN_DELIM words TOKEN_DELIM + '{' statements '}' { + /* we just flatten everything */ + $$ = create_statement_block(parser, $6); + } words: word { $$ = create_argv(parser); @@ -108,3 +146,163 @@ void yyerror(struct grub2_parser *parser, char const *s) yyget_lineno(parser->scanner), s, yyget_text(parser->scanner)); } + +struct grub2_statements *create_statements(struct grub2_parser *parser) +{ + struct grub2_statements *stmts = talloc(parser, + struct grub2_statements); + list_init(&stmts->list); + return stmts; +} + +struct grub2_statement *create_statement_simple(struct grub2_parser *parser, + struct grub2_argv *argv) +{ + struct grub2_statement_simple *stmt = + talloc(parser, struct grub2_statement_simple); + stmt->st.type = STMT_TYPE_SIMPLE; + stmt->st.exec = statement_simple_execute; + stmt->argv = argv; + return &stmt->st; +} + +struct grub2_statement *create_statement_menuentry(struct grub2_parser *parser, + struct grub2_argv *argv, struct grub2_statements *stmts) +{ + struct grub2_statement_menuentry *stmt = + talloc(parser, struct grub2_statement_menuentry); + stmt->st.type = STMT_TYPE_MENUENTRY; + stmt->st.exec = statement_menuentry_execute; + stmt->argv = argv; + stmt->statements = stmts; + return &stmt->st; +} + +struct grub2_statement *create_statement_conditional( + struct grub2_parser *parser, + struct grub2_statement *condition, + struct grub2_statements *statements) +{ + struct grub2_statement_conditional *stmt = + talloc(parser, struct grub2_statement_conditional); + stmt->st.type = STMT_TYPE_CONDITIONAL; + stmt->condition = condition; + stmt->statements = statements; + return &stmt->st; +} + +struct grub2_statement *create_statement_if(struct grub2_parser *parser, + struct grub2_statement *conditional, + struct grub2_statements *elifs, + struct grub2_statements *else_case) +{ + struct grub2_statement_if *stmt = + talloc(parser, struct grub2_statement_if); + + list_add(&elifs->list, &conditional->list); + + stmt->st.type = STMT_TYPE_IF; + stmt->st.exec = statement_if_execute; + stmt->conditionals = elifs; + stmt->else_case = else_case; + return &stmt->st; +} + +struct grub2_statement *create_statement_block(struct grub2_parser *parser, + struct grub2_statements *stmts) +{ + struct grub2_statement_block *stmt = + talloc(parser, struct grub2_statement_block); + stmt->st.type = STMT_TYPE_BLOCK; + stmt->st.exec = NULL; + stmt->statements = stmts; + return &stmt->st; +} + +struct grub2_statement *create_statement_function(struct grub2_parser *parser, + struct grub2_word *name, struct grub2_statements *body) +{ + struct grub2_statement_function *stmt = + talloc(parser, struct grub2_statement_function); + stmt->st.exec = statement_function_execute; + stmt->name = name; + stmt->body = body; + return &stmt->st; +} + +void statement_append(struct grub2_statements *stmts, + struct grub2_statement *stmt) +{ + if (!stmt) + return; + list_add_tail(&stmts->list, &stmt->list); +} + +struct grub2_word *create_word_text(struct grub2_parser *parser, + const char *text) +{ + struct grub2_word *word = talloc(parser, struct grub2_word); + word->type = GRUB2_WORD_TEXT; + word->split = false; + word->text = talloc_strdup(word, text); + word->next = NULL; + word->last = word; + return word; +} + +struct grub2_word *create_word_var(struct grub2_parser *parser, + const char *name, bool split) +{ + struct grub2_word *word = talloc(parser, struct grub2_word); + word->type = GRUB2_WORD_VAR; + word->name = talloc_strdup(word, name); + word->split = split; + word->next = NULL; + word->last = word; + return word; +} + +struct grub2_argv *create_argv(struct grub2_parser *parser) +{ + struct grub2_argv *argv = talloc(parser, struct grub2_argv); + list_init(&argv->words); + return argv; +} + +void argv_append(struct grub2_argv *argv, struct grub2_word *word) +{ + list_add_tail(&argv->words, &word->argv_list); +} + +void word_append(struct grub2_word *w1, struct grub2_word *w2) +{ + w1->last->next = w2; + w1->last = w2; +} + +struct grub2_parser *grub2_parser_create(struct discover_context *ctx) +{ + struct grub2_parser *parser; + + parser = talloc(ctx, struct grub2_parser); + yylex_init_extra(parser, &parser->scanner); + parser->script = create_script(parser, ctx); + + return parser; +} + +void grub2_parser_parse(struct grub2_parser *parser, char *buf, int len) +{ + YY_BUFFER_STATE bufstate; + int rc; + + bufstate = yy_scan_bytes(buf, len - 1, parser->scanner); + + rc = yyparse(parser); + + yy_delete_buffer(bufstate, parser->scanner); + + if (!rc) + script_execute(parser->script); +} +