X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fgrub2%2Fparser.y;h=859eba30479b93eeac8fa4a8c00d21d7916931d4;hp=a8c02e284b6d7b4507003839e1d5eb483814617f;hb=a77e8d42cd7b983d9fa5746f07e66a6fe04b6a0d;hpb=ce2275ed4fa099035af123c25a1a7657f1ea6e78 diff --git a/discover/grub2/parser.y b/discover/grub2/parser.y index a8c02e2..859eba3 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" @@ -56,7 +61,7 @@ static void yyerror(struct grub2_parser *, char const *s); %% script: statements { - parser->statements = $1; + parser->script->statements = $1; } statements: statement { @@ -65,6 +70,7 @@ statements: statement { } | statements statement { statement_append($1, $2); + $$ = $1; } statement: TOKEN_EOL { @@ -73,18 +79,37 @@ statement: TOKEN_EOL { | words TOKEN_EOL { $$ = create_statement_simple(parser, $1); } - | '{' statements '}' { $$ = NULL; } + | '{' statements '}' { + $$ = create_statement_block(parser, $2); + } | "if" TOKEN_DELIM statement "then" TOKEN_EOL statements "fi" TOKEN_EOL { $$ = create_statement_if(parser, $3, $6, NULL); } + | "if" TOKEN_DELIM statement + "then" TOKEN_EOL + statements + "else" TOKEN_EOL + statements + "fi" TOKEN_EOL { + $$ = create_statement_if(parser, $3, $6, $9); + } + | "function" TOKEN_DELIM word TOKEN_DELIM '{' statements '}' { + $$ = create_statement_function(parser, $3, $6); + } | "menuentry" TOKEN_DELIM words TOKEN_DELIM '{' statements '}' TOKEN_EOL { $$ = create_statement_menuentry(parser, $3, $6); } + | "submenu" TOKEN_DELIM words TOKEN_DELIM + '{' statements '}' + TOKEN_EOL { + /* we just flatten everything */ + $$ = create_statement_block(parser, $6); + } words: word { $$ = create_argv(parser); @@ -108,3 +133,148 @@ 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_if(struct grub2_parser *parser, + struct grub2_statement *condition, + struct grub2_statements *true_case, + struct grub2_statements *false_case) +{ + struct grub2_statement_if *stmt = + talloc(parser, struct grub2_statement_if); + stmt->st.type = STMT_TYPE_IF; + stmt->st.exec = statement_if_execute; + stmt->condition = condition; + stmt->true_case = true_case; + stmt->false_case = false_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); +} +