From bfa2bd9efba361b1cb534279e97fe5b42210b19c Mon Sep 17 00:00:00 2001 From: marco_g Date: Mon, 17 Apr 2006 13:01:20 +0000 Subject: [PATCH] 2006-17-04 Marco Gerards * include/grub/script.h: Include and "grub_script.tab.h". (struct grub_lexer_param): New struct. (struct grub_parser_param): Likewise. (grub_script_create_arglist): Pass the state in an argument. (grub_script_add_arglist): Likewise. (grub_script_create_cmdline): Likewise. (grub_script_create_cmdblock): Likewise. (grub_script_create_cmdif): Likewise. (grub_script_create_cmdmenu): Likewise. (grub_script_add_cmd): Likewise. (grub_script_arg_add): Likewise. (grub_script_lexer_ref): Likewise. (grub_script_lexer_deref): Likewise. (grub_script_lexer_record_start): Likewise. (grub_script_lexer_record_stop): Likewise. (grub_script_mem_record): Likewise. (grub_script_mem_record_stop): Likewise. (grub_script_malloc): Likewise. (grub_script_yylex): Likewise. (grub_script_yyparse): Likewise. (grub_script_yyerror): Likewise. (grub_script_yylex): Likewise. (grub_script_lexer_init): Return the state. * normal/lexer.c (grub_script_lexer_state): Removed variable. (grub_script_lexer_done): Likewise. (grub_script_lexer_getline): Likewise. (grub_script_lexer_refs): Likewise. (script): Likewise. (newscript): Likewise. (record): Likewise. (recording): Likewise. (recordpos): Likewise. (recordlen): Likewise. (grub_script_lexer_init): Return the state instead of setting global variables. (grub_script_lexer_ref): Use the newly added argument for state instead of globals. (grub_script_lexer_deref): Likewise. (grub_script_lexer_record_start): Likewise. (grub_script_lexer_record_stop): Likewise. (recordchar): Likewise. (nextchar): Likewise. (grub_script_yylex2): Likewise. (grub_script_yylex): Likewise. (grub_script_yyerror): Likewise. * normal/parser.y (func_mem): Removed variable. (menu_entry): Likewise. (err): Likewise. (%lex-param): New parser option. (%parse-param): Likewise. (script): Always return the AST. (argument): Pass the state around. (arguments): Likewise. (grubcmd): Likewise. (commands): Likewise. (function): Likewise. (menuentry): Likewise. (if_statement): Likewise. (if): Likewise. * normal/script.c (grub_script_memused): Removed variable. (grub_script_parsed): Likewise. (grub_script_malloc): Added a state argument. Use that instead of global variables. (grub_script_mem_record): Likewise. (grub_script_mem_record_stop): Likewise. (grub_script_arg_add): Likewise. (grub_script_add_arglist): Likewise. (grub_script_create_cmdline): Likewise. (grub_script_create_cmdif): Likewise. (grub_script_create_cmdmenu): Likewise. (grub_script_add_cmd): Likewise. (grub_script_parse): Setup the state before calling the parser. --- ChangeLog | 79 ++++++++++++++++ include/grub/script.h | 109 +++++++++++++++++----- normal/lexer.c | 205 +++++++++++++++++++++--------------------- normal/parser.y | 66 +++++++------- normal/script.c | 107 +++++++++++++--------- 5 files changed, 369 insertions(+), 197 deletions(-) diff --git a/ChangeLog b/ChangeLog index 77bf87739..3968b8dc4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,82 @@ +2006-17-04 Marco Gerards + + * include/grub/script.h: Include and + "grub_script.tab.h". + (struct grub_lexer_param): New struct. + (struct grub_parser_param): Likewise. + (grub_script_create_arglist): Pass the state in an argument. + (grub_script_add_arglist): Likewise. + (grub_script_create_cmdline): Likewise. + (grub_script_create_cmdblock): Likewise. + (grub_script_create_cmdif): Likewise. + (grub_script_create_cmdmenu): Likewise. + (grub_script_add_cmd): Likewise. + (grub_script_arg_add): Likewise. + (grub_script_lexer_ref): Likewise. + (grub_script_lexer_deref): Likewise. + (grub_script_lexer_record_start): Likewise. + (grub_script_lexer_record_stop): Likewise. + (grub_script_mem_record): Likewise. + (grub_script_mem_record_stop): Likewise. + (grub_script_malloc): Likewise. + (grub_script_yylex): Likewise. + (grub_script_yyparse): Likewise. + (grub_script_yyerror): Likewise. + (grub_script_yylex): Likewise. + (grub_script_lexer_init): Return the state. + + * normal/lexer.c (grub_script_lexer_state): Removed variable. + (grub_script_lexer_done): Likewise. + (grub_script_lexer_getline): Likewise. + (grub_script_lexer_refs): Likewise. + (script): Likewise. + (newscript): Likewise. + (record): Likewise. + (recording): Likewise. + (recordpos): Likewise. + (recordlen): Likewise. + (grub_script_lexer_init): Return the state instead of setting + global variables. + (grub_script_lexer_ref): Use the newly added argument for state + instead of globals. + (grub_script_lexer_deref): Likewise. + (grub_script_lexer_record_start): Likewise. + (grub_script_lexer_record_stop): Likewise. + (recordchar): Likewise. + (nextchar): Likewise. + (grub_script_yylex2): Likewise. + (grub_script_yylex): Likewise. + (grub_script_yyerror): Likewise. + + * normal/parser.y (func_mem): Removed variable. + (menu_entry): Likewise. + (err): Likewise. + (%lex-param): New parser option. + (%parse-param): Likewise. + (script): Always return the AST. + (argument): Pass the state around. + (arguments): Likewise. + (grubcmd): Likewise. + (commands): Likewise. + (function): Likewise. + (menuentry): Likewise. + (if_statement): Likewise. + (if): Likewise. + + * normal/script.c (grub_script_memused): Removed variable. + (grub_script_parsed): Likewise. + (grub_script_malloc): Added a state argument. Use that instead of + global variables. + (grub_script_mem_record): Likewise. + (grub_script_mem_record_stop): Likewise. + (grub_script_arg_add): Likewise. + (grub_script_add_arglist): Likewise. + (grub_script_create_cmdline): Likewise. + (grub_script_create_cmdif): Likewise. + (grub_script_create_cmdmenu): Likewise. + (grub_script_add_cmd): Likewise. + (grub_script_parse): Setup the state before calling the parser. + 2006-16-04 Marco Gerards * normal/command.c (grub_command_init): Remove the title command. diff --git a/include/grub/script.h b/include/grub/script.h index 5108eee92..661d0ee33 100644 --- a/include/grub/script.h +++ b/include/grub/script.h @@ -23,6 +23,8 @@ #include #include +#include +#include "grub_script.tab.h" struct grub_script_mem; @@ -123,33 +125,98 @@ struct grub_script_cmd_menuentry int options; }; -struct grub_script_arglist * -grub_script_create_arglist (void); +/* State of the lexer as passed to the lexer. */ +struct grub_lexer_param +{ + /* Set to 0 when the lexer is done. */ + int done; + + /* State of the state machine. */ + grub_parser_state_t state; + + /* Function used by the lexer to get a new line when more input is + expected, but not available. */ + grub_err_t (*getline) (char **); + + /* A reference counter. If this is >0 it means that the parser + expects more tokens and `getline' should be called to fetch more. + Otherwise the lexer can stop processing if the current buffer is + depleted. */ + int refs; + + /* The character stream that has to be parsed. */ + char *script; + char *newscript; /* XXX */ + + /* While walking through the databuffer, `record' the characters to + this other buffer. It can be used to edit the menu entry at a + later moment. */ + + /* If true, recording is enabled. */ + int record; + + /* Points to the recording. */ + char *recording; + + /* index in the RECORDING. */ + int recordpos; + + /* Size of RECORDING. */ + int recordlen; +}; + +/* State of the parser as passes to the parser. */ +struct grub_parser_param +{ + /* Keep track of the memory allocated for this specific + function. */ + struct grub_script_mem *func_mem; + + /* When set to 0, no errors have occured during parsing. */ + int err; + + /* The memory that was used while parsing and scanning. */ + struct grub_script_mem *memused; + + /* The result of the parser. */ + struct grub_script_cmd *parsed; + + struct grub_lexer_param *lexerstate; +}; struct grub_script_arglist * -grub_script_add_arglist (struct grub_script_arglist *list, +grub_script_create_arglist (struct grub_parser_param *state); + +struct grub_script_arglist * +grub_script_add_arglist (struct grub_parser_param *state, + struct grub_script_arglist *list, struct grub_script_arg *arg); struct grub_script_cmd * -grub_script_create_cmdline (char *cmdname, +grub_script_create_cmdline (struct grub_parser_param *state, + char *cmdname, struct grub_script_arglist *arglist); struct grub_script_cmd * -grub_script_create_cmdblock (void); +grub_script_create_cmdblock (struct grub_parser_param *state); struct grub_script_cmd * -grub_script_create_cmdif (struct grub_script_cmd *bool, +grub_script_create_cmdif (struct grub_parser_param *state, + struct grub_script_cmd *bool, struct grub_script_cmd *true, struct grub_script_cmd *false); struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_script_arg *title, +grub_script_create_cmdmenu (struct grub_parser_param *state, + struct grub_script_arg *title, char *sourcecode, int options); struct grub_script_cmd * -grub_script_add_cmd (struct grub_script_cmdblock *cmdblock, +grub_script_add_cmd (struct grub_parser_param *state, + struct grub_script_cmdblock *cmdblock, struct grub_script_cmd *cmd); struct grub_script_arg * -grub_script_arg_add (struct grub_script_arg *arg, +grub_script_arg_add (struct grub_parser_param *state, + struct grub_script_arg *arg, grub_script_arg_type_t type, char *str); struct grub_script *grub_script_parse (char *script, @@ -158,21 +225,23 @@ void grub_script_free (struct grub_script *script); struct grub_script *grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem); -void grub_script_lexer_init (char *s, grub_err_t (*getline) (char **)); -void grub_script_lexer_ref (void); -void grub_script_lexer_deref (void); -void grub_script_lexer_record_start (void); -char *grub_script_lexer_record_stop (void); +struct grub_lexer_param *grub_script_lexer_init (char *s, + grub_err_t (*getline) (char **)); +void grub_script_lexer_ref (struct grub_lexer_param *); +void grub_script_lexer_deref (struct grub_lexer_param *); +void grub_script_lexer_record_start (struct grub_lexer_param *); +char *grub_script_lexer_record_stop (struct grub_lexer_param *); /* Functions to track allocated memory. */ -void *grub_script_malloc (grub_size_t size); -struct grub_script_mem *grub_script_mem_record (void); -struct grub_script_mem *grub_script_mem_record_stop (struct grub_script_mem *restore); +struct grub_script_mem *grub_script_mem_record (struct grub_parser_param *state); +struct grub_script_mem *grub_script_mem_record_stop (struct grub_parser_param *state, + struct grub_script_mem *restore); +void *grub_script_malloc (struct grub_parser_param *state, grub_size_t size); /* Functions used by bison. */ -int grub_script_yylex (void); -int grub_script_yyparse (void); -void grub_script_yyerror (char const *err); +int grub_script_yylex (YYSTYPE *, struct grub_parser_param *); +int grub_script_yyparse (struct grub_parser_param *); +void grub_script_yyerror (struct grub_parser_param *, char const *); /* Commands to execute, don't use these directly. */ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd); diff --git a/normal/lexer.c b/normal/lexer.c index f23e5a300..bb1bbc460 100644 --- a/normal/lexer.c +++ b/normal/lexer.c @@ -25,10 +25,6 @@ #include "grub_script.tab.h" -static grub_parser_state_t grub_script_lexer_state; -static int grub_script_lexer_done = 0; -static grub_err_t (*grub_script_lexer_getline) (char **); - static int check_varstate (grub_parser_state_t state) { @@ -48,109 +44,109 @@ check_textstate (grub_parser_state_t state) || state == GRUB_PARSER_STATE_DQUOTE); } -/* The amount of references to the lexer by the parser. If the parser - expects tokens the lexer is referenced. */ -static int grub_script_lexer_refs = 0; -static char *script; -static char *newscript; - -static int record = 0; -static char *recording = 0; -static int recordpos = 0; -static int recordlen = 0; - -/* XXX: The lexer is not reentrant. */ -void -grub_script_lexer_init (char *s, grub_err_t (*getline) (char **)) +struct grub_lexer_param * +grub_script_lexer_init (char *script, grub_err_t (*getline) (char **)) { - grub_script_lexer_state = GRUB_PARSER_STATE_TEXT; - grub_script_lexer_getline = getline; - grub_script_lexer_refs = 0; - grub_script_lexer_done = 0; - newscript = 0; - script = s; + struct grub_lexer_param *param; + + param = grub_malloc (sizeof (*param)); + if (! param) + return 0; + + param->state = GRUB_PARSER_STATE_TEXT; + param->getline = getline; + param->refs = 0; + param->done = 0; + param->newscript = 0; + param->script = script; + param->record = 0; + param->recording = 0; + param->recordpos = 0; + param->recordlen = 0; + + return param; } void -grub_script_lexer_ref (void) +grub_script_lexer_ref (struct grub_lexer_param *state) { - grub_script_lexer_refs++; + state->refs++; } void -grub_script_lexer_deref (void) +grub_script_lexer_deref (struct grub_lexer_param *state) { - grub_script_lexer_refs--; + state->refs--; } /* Start recording all characters passing through the lexer. */ void -grub_script_lexer_record_start (void) +grub_script_lexer_record_start (struct grub_lexer_param *state) { - record = 1; - recordlen = 100; - recording = grub_malloc (recordlen); - recordpos = 0; + state->record = 1; + state->recordlen = 100; + state->recording = grub_malloc (state->recordlen); + state->recordpos = 0; } char * -grub_script_lexer_record_stop (void) +grub_script_lexer_record_stop (struct grub_lexer_param *state) { - record = 0; + state->record = 0; /* Delete the last character, it is a `}'. */ - if (recordpos > 0) + if (state->recordpos > 0) { - if (recording[--recordpos] != '}') + if (state->recording[--state->recordpos] != '}') { grub_printf ("Internal error while parsing menu entry"); for (;;); /* XXX */ } - recording[recordpos] = '\0'; + state->recording[state->recordpos] = '\0'; } - return recording; + return state->recording; } /* When recording is enabled, record the character C as the next item in the character stream. */ static void -recordchar (char c) +recordchar (struct grub_lexer_param *state, char c) { - if (recordpos == recordlen) + if (state->recordpos == state->recordlen) { - char *old = recording; - recordlen += 100; - recording = grub_realloc (recording, recordlen); - if (! recording) + char *old = state->recording; + state->recordlen += 100; + state->recording = grub_realloc (state->recording, state->recordlen); + if (! state->recording) { grub_free (old); - record = 0; + state->record = 0; } } - recording[recordpos++] = c; + state->recording[state->recordpos++] = c; } /* Fetch the next character for the lexer. */ static void -nextchar (void) +nextchar (struct grub_lexer_param *state) { - if (record) - recordchar (*script); - script++; + if (state->record) + recordchar (state, *state->script); + state->script++; } int -grub_script_yylex2 (void); +grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate); int -grub_script_yylex (void) +grub_script_yylex (YYSTYPE *yylval, struct grub_parser_param *parsestate) { int r = -1; while (r == -1) { - r = grub_script_yylex2 (); + r = grub_script_yylex2 (yylval, parsestate); if (r == ' ' || r == '\n') r = -1; } @@ -158,48 +154,49 @@ grub_script_yylex (void) } int -grub_script_yylex2 (void) +grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate) { grub_parser_state_t newstate; char use; char *buffer; char *bp; + struct grub_lexer_param *state = parsestate->lexerstate; - if (grub_script_lexer_done) + if (state->done) return 0; - if (! *script) + if (! *state->script) { /* Check if more tokens are requested by the parser. */ - if ((grub_script_lexer_refs - || grub_script_lexer_state == GRUB_PARSER_STATE_ESC) - && grub_script_lexer_getline) + if ((state->refs + || state->state == GRUB_PARSER_STATE_ESC) + && state->getline) { - while (!script || ! grub_strlen (script)) + while (!state->script || ! grub_strlen (state->script)) { - grub_free (newscript); - newscript = 0; - grub_script_lexer_getline (&newscript); - script = newscript; - if (! script) + grub_free (state->newscript); + state->newscript = 0; + state->getline (&state->newscript); + state->script = state->newscript; + if (! state->script) return 0; } grub_dprintf ("scripting", "token=`\\n'\n"); - recordchar ('\n'); - if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC) + recordchar (state, '\n'); + if (state->state != GRUB_PARSER_STATE_ESC) return '\n'; } else { - grub_free (newscript); - newscript = 0; - grub_script_lexer_done = 1; + grub_free (state->newscript); + state->newscript = 0; + state->done = 1; grub_dprintf ("scripting", "token=`\\n'\n"); return '\n'; } } - newstate = grub_parser_cmdline_state (grub_script_lexer_state, *script, &use); + newstate = grub_parser_cmdline_state (state->state, *state->script, &use); /* Check if it is a text. */ if (check_textstate (newstate)) @@ -208,21 +205,21 @@ grub_script_yylex2 (void) length symbol. */ if (newstate == GRUB_PARSER_STATE_TEXT) { - switch (*script) + switch (*state->script) { case ' ': - while (*script) + while (*state->script) { - newstate = grub_parser_cmdline_state (grub_script_lexer_state, - *script, &use); - if (! (grub_script_lexer_state == GRUB_PARSER_STATE_TEXT - && *script == ' ')) + newstate = grub_parser_cmdline_state (state->state, + *state->script, &use); + if (! (state->state == GRUB_PARSER_STATE_TEXT + && *state->script == ' ')) { grub_dprintf ("scripting", "token=` '\n"); return ' '; } - grub_script_lexer_state = newstate; - nextchar (); + state->state = newstate; + nextchar (state); } grub_dprintf ("scripting", "token=` '\n"); return ' '; @@ -232,26 +229,26 @@ grub_script_yylex2 (void) case '\n': { char c; - grub_dprintf ("scripting", "token=`%c'\n", *script); - c = *script;; - nextchar (); + grub_dprintf ("scripting", "token=`%c'\n", *state->script); + c = *state->script;; + nextchar (state); return c; } } } /* XXX: Use a better size. */ - buffer = grub_script_malloc (2048); + buffer = grub_script_malloc (parsestate, 2048); if (! buffer) return 0; bp = buffer; /* Read one token, possible quoted. */ - while (*script) + while (*state->script) { - newstate = grub_parser_cmdline_state (grub_script_lexer_state, - *script, &use); + newstate = grub_parser_cmdline_state (state->state, + *state->script, &use); /* Check if a variable name starts. */ if (check_varstate (newstate)) @@ -261,7 +258,7 @@ grub_script_yylex2 (void) when a special token was found. It will be recognised next time when this function is called. */ if (newstate == GRUB_PARSER_STATE_TEXT - && grub_script_lexer_state != GRUB_PARSER_STATE_ESC) + && state->state != GRUB_PARSER_STATE_ESC) { int breakout = 0; @@ -281,14 +278,14 @@ grub_script_yylex2 (void) else if (use) *(bp++) = use; - grub_script_lexer_state = newstate; - nextchar (); + state->state = newstate; + nextchar (state); } /* A string of text was read in. */ *bp = '\0'; grub_dprintf ("scripting", "token=`%s'\n", buffer); - grub_script_yylval.string = buffer; + yylval->string = buffer; /* Detect some special tokens. */ if (! grub_strcmp (buffer, "while")) @@ -314,38 +311,38 @@ grub_script_yylex2 (void) || newstate == GRUB_PARSER_STATE_QVAR) { /* XXX: Use a better size. */ - buffer = grub_script_malloc (2096); + buffer = grub_script_malloc (parsestate, 2096); if (! buffer) return 0; bp = buffer; /* This is a variable, read the variable name. */ - while (*script) + while (*state->script) { - newstate = grub_parser_cmdline_state (grub_script_lexer_state, - *script, &use); + newstate = grub_parser_cmdline_state (state->state, + *state->script, &use); /* Check if this character is not part of the variable name anymore. */ if (! (check_varstate (newstate))) { - if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2 - || grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2) - nextchar (); - grub_script_lexer_state = newstate; + if (state->state == GRUB_PARSER_STATE_VARNAME2 + || state->state == GRUB_PARSER_STATE_QVARNAME2) + nextchar (state); + state->state = newstate; break; } if (use) *(bp++) = use; - nextchar (); - grub_script_lexer_state = newstate; + nextchar (state); + state->state = newstate; } *bp = '\0'; - grub_script_lexer_state = newstate; - grub_script_yylval.string = buffer; + state->state = newstate; + yylval->string = buffer; grub_dprintf ("scripting", "vartoken=`%s'\n", buffer); return GRUB_PARSER_TOKEN_VAR; @@ -360,7 +357,7 @@ grub_script_yylex2 (void) } void -grub_script_yyerror (char const *err) +grub_script_yyerror (struct grub_parser_param *lex, char const *err) { grub_printf ("%s\n", err); } diff --git a/normal/parser.y b/normal/parser.y index 08aae7605..2c1fb0aa8 100644 --- a/normal/parser.y +++ b/normal/parser.y @@ -25,12 +25,6 @@ #define YYFREE grub_free #define YYMALLOC grub_malloc -/* Keep track of the memory allocated for this specific function. */ -static struct grub_script_mem *func_mem; - -static char *menu_entry; - -static int err; %} @@ -56,11 +50,15 @@ static int err; %type "if" "while" "function" "else" "then" "fi" %type text GRUB_PARSER_TOKEN_NAME GRUB_PARSER_TOKEN_VAR +%pure-parser +%lex-param { struct grub_parser_param *state }; +%parse-param { struct grub_parser_param *state }; + %% /* It should be possible to do this in a clean way... */ -script: { err = 0} commands +script: { state->err = 0} commands { - grub_script_parsed = err ? 0 : $2; + state->parsed = $2; } ; @@ -84,11 +82,11 @@ text: GRUB_PARSER_TOKEN_NAME for example: `foo${bar}baz'. */ argument: GRUB_PARSER_TOKEN_VAR { - $$ = grub_script_arg_add (0, GRUB_SCRIPT_ARG_TYPE_VAR, $1); + $$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_VAR, $1); } | text { - $$ = grub_script_arg_add (0, GRUB_SCRIPT_ARG_TYPE_STR, $1); + $$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_STR, $1); } /* XXX: Currently disabled to simplify the parser. This should be parsed by yet another parser for readibility. */ @@ -104,21 +102,21 @@ argument: GRUB_PARSER_TOKEN_VAR arguments: argument { - $$ = grub_script_add_arglist (0, $1); + $$ = grub_script_add_arglist (state, 0, $1); } | arguments argument { - $$ = grub_script_add_arglist ($1, $2); + $$ = grub_script_add_arglist (state, $1, $2); } ; grubcmd: GRUB_PARSER_TOKEN_NAME arguments { - $$ = grub_script_create_cmdline ($1, $2); + $$ = grub_script_create_cmdline (state, $1, $2); } | GRUB_PARSER_TOKEN_NAME { - $$ = grub_script_create_cmdline ($1, 0); + $$ = grub_script_create_cmdline (state, $1, 0); } ; @@ -132,18 +130,18 @@ command: grubcmd { $$ = $1; } /* A block of commands. */ commands: command { - $$ = grub_script_add_cmd (0, $1); + $$ = grub_script_add_cmd (state, 0, $1); } | command ';' commands { struct grub_script_cmdblock *cmd; cmd = (struct grub_script_cmdblock *) $1; - $$ = grub_script_add_cmd (cmd, $3); + $$ = grub_script_add_cmd (state, cmd, $3); } | error { - yyerror ("Incorrect command"); - err = 1; + yyerror (state, "Incorrect command"); + state->err = 1; yyerrok; } ; @@ -151,59 +149,61 @@ commands: command /* A function. Carefully save the memory that is allocated. */ function: "function" GRUB_PARSER_TOKEN_NAME { - grub_script_lexer_ref (); + grub_script_lexer_ref (state->lexerstate); } '{' { /* The first part of the function was recognised. Now start recording the memory usage to store this function. */ - func_mem = grub_script_mem_record (); + state->func_mem = grub_script_mem_record (state); } commands '}' { struct grub_script *script; /* All the memory usage for parsing this function was recorded. */ - func_mem = grub_script_mem_record_stop (func_mem); - script = grub_script_create ($6, func_mem); + state->func_mem = grub_script_mem_record_stop (state, + state->func_mem); + script = grub_script_create ($6, state->func_mem); if (script) grub_script_function_create ($2, script); - grub_script_lexer_deref (); + grub_script_lexer_deref (state->lexerstate); } ; /* A menu entry. Carefully save the memory that is allocated. */ menuentry: "menuentry" argument { - grub_script_lexer_ref (); + grub_script_lexer_ref (state->lexerstate); } '{' { /* Record sourcecode of the menu entry. It can be parsed multiple times if it is part of a loop. */ - grub_script_lexer_record_start (); + grub_script_lexer_record_start (state->lexerstate); } commands '}' { - menu_entry = grub_script_lexer_record_stop (); - $$ = grub_script_create_cmdmenu ($2, menu_entry, 0); - grub_script_lexer_deref (); + char *menu_entry; + menu_entry = grub_script_lexer_record_stop (state->lexerstate); + $$ = grub_script_create_cmdmenu (state, $2, menu_entry, 0); + grub_script_lexer_deref (state->lexerstate); } ; /* The first part of the if statement. It's used to switch the lexer to a state in which it demands more tokens. */ -if_statement: "if" { grub_script_lexer_ref (); } +if_statement: "if" { grub_script_lexer_ref (state->lexerstate); } ; /* The if statement. */ if: if_statement grubcmd ';' "then" commands "fi" { - $$ = grub_script_create_cmdif ($2, $5, 0); - grub_script_lexer_deref (); + $$ = grub_script_create_cmdif (state, $2, $5, 0); + grub_script_lexer_deref (state->lexerstate); } | if_statement grubcmd ';' "then" commands "else" commands "fi" { - $$ = grub_script_create_cmdif ($2, $5, $7); - grub_script_lexer_deref (); + $$ = grub_script_create_cmdif (state, $2, $5, $7); + grub_script_lexer_deref (state->lexerstate); } ; diff --git a/normal/script.c b/normal/script.c index d427994a7..e9b33ac51 100644 --- a/normal/script.c +++ b/normal/script.c @@ -28,11 +28,7 @@ allocations. The memory is free'ed in case of an error, or assigned to the parsed script when parsing was successful. */ -/* The memory that was used while parsing and scanning. */ -static struct grub_script_mem *grub_script_memused; - -/* The result of the parser. */ -struct grub_script_cmd *grub_script_parsed = 0; +/* XXX */ /* In case of the normal malloc, some additional bytes are allocated for this datastructure. All reserved memory is stored in a linked @@ -46,15 +42,15 @@ struct grub_script_mem /* Return malloc'ed memory and keep track of the allocation. */ void * -grub_script_malloc (grub_size_t size) +grub_script_malloc (struct grub_parser_param *state, grub_size_t size) { struct grub_script_mem *mem; mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem) - sizeof (char)); grub_dprintf ("scripting", "malloc %p\n", mem); - mem->next = grub_script_memused; - grub_script_memused = mem; + mem->next = state->memused; + state->memused = mem; return (void *) &mem->mem; } @@ -76,20 +72,22 @@ grub_script_mem_free (struct grub_script_mem *mem) /* Start recording memory usage. Returns the memory that should be restored when calling stop. */ struct grub_script_mem * -grub_script_mem_record (void) +grub_script_mem_record (struct grub_parser_param *state) { - struct grub_script_mem *mem = grub_script_memused; - grub_script_memused = 0; + struct grub_script_mem *mem = state->memused; + state->memused = 0; + return mem; } /* Stop recording memory usage. Restore previous recordings using RESTORE. Return the recorded memory. */ struct grub_script_mem * -grub_script_mem_record_stop (struct grub_script_mem *restore) +grub_script_mem_record_stop (struct grub_parser_param *state, + struct grub_script_mem *restore) { - struct grub_script_mem *mem = grub_script_memused; - grub_script_memused = restore; + struct grub_script_mem *mem = state->memused; + state->memused = restore; return mem; } @@ -108,13 +106,13 @@ grub_script_free (struct grub_script *script) /* Extend the argument arg with a variable or string of text. If ARG is zero a new list is created. */ struct grub_script_arg * -grub_script_arg_add (struct grub_script_arg *arg, +grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *arg, grub_script_arg_type_t type, char *str) { struct grub_script_arg *argpart; struct grub_script_arg *ll; - argpart = (struct grub_script_arg *) grub_script_malloc (sizeof (*arg)); + argpart = (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg)); argpart->type = type; argpart->str = str; argpart->next = 0; @@ -131,14 +129,15 @@ grub_script_arg_add (struct grub_script_arg *arg, /* Add the argument ARG to the end of the argument list LIST. If LIST is zero, a new list will be created. */ struct grub_script_arglist * -grub_script_add_arglist (struct grub_script_arglist *list, struct grub_script_arg *arg) +grub_script_add_arglist (struct grub_parser_param *state, + struct grub_script_arglist *list, struct grub_script_arg *arg) { struct grub_script_arglist *link; struct grub_script_arglist *ll; grub_dprintf ("scripting", "arglist\n"); - link = (struct grub_script_arglist *) grub_script_malloc (sizeof (*link)); + link = (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link)); link->next = 0; link->arg = arg; link->argcount = 0; @@ -162,13 +161,14 @@ grub_script_add_arglist (struct grub_script_arglist *list, struct grub_script_ar contains the name of the command that should be executed. ARGLIST holds all arguments for this command. */ struct grub_script_cmd * -grub_script_create_cmdline (char *cmdname, struct grub_script_arglist *arglist) +grub_script_create_cmdline (struct grub_parser_param *state, + char *cmdname, struct grub_script_arglist *arglist) { struct grub_script_cmdline *cmd; grub_dprintf ("scripting", "cmdline\n"); - cmd = grub_script_malloc (sizeof (*cmd)); + cmd = grub_script_malloc (state, sizeof (*cmd)); cmd->cmd.exec = grub_script_execute_cmdline; cmd->cmd.next = 0; cmd->arglist = arglist; @@ -182,7 +182,8 @@ grub_script_create_cmdline (char *cmdname, struct grub_script_arglist *arglist) interpreter will run the command TRUE, otherwise the interpreter runs the command FALSE. */ struct grub_script_cmd * -grub_script_create_cmdif (struct grub_script_cmd *bool, +grub_script_create_cmdif (struct grub_parser_param *state, + struct grub_script_cmd *bool, struct grub_script_cmd *true, struct grub_script_cmd *false) { @@ -190,7 +191,7 @@ grub_script_create_cmdif (struct grub_script_cmd *bool, grub_dprintf ("scripting", "cmdif\n"); - cmd = grub_script_malloc (sizeof (*cmd)); + cmd = grub_script_malloc (state, sizeof (*cmd)); cmd->cmd.exec = grub_script_execute_cmdif; cmd->cmd.next = 0; cmd->bool = bool; @@ -205,7 +206,8 @@ grub_script_create_cmdif (struct grub_script_cmd *bool, the title. The sourcecode for this entry is passed in SOURCECODE. The options for this entry are passed in OPTIONS. */ struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_script_arg *title, +grub_script_create_cmdmenu (struct grub_parser_param *state, + struct grub_script_arg *title, char *sourcecode, int options) { @@ -221,7 +223,7 @@ grub_script_create_cmdmenu (struct grub_script_arg *title, sourcecode[i] = '\0'; } - cmd = grub_script_malloc (sizeof (*cmd)); + cmd = grub_script_malloc (state, sizeof (*cmd)); cmd->cmd.exec = grub_script_execute_menuentry; cmd->cmd.next = 0; cmd->sourcecode = sourcecode; @@ -235,7 +237,9 @@ grub_script_create_cmdmenu (struct grub_script_arg *title, be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new cmdblock will be created. */ struct grub_script_cmd * -grub_script_add_cmd (struct grub_script_cmdblock *cmdblock, struct grub_script_cmd *cmd) +grub_script_add_cmd (struct grub_parser_param *state, + struct grub_script_cmdblock *cmdblock, + struct grub_script_cmd *cmd) { grub_dprintf ("scripting", "cmdblock\n"); @@ -244,7 +248,8 @@ grub_script_add_cmd (struct grub_script_cmdblock *cmdblock, struct grub_script_c if (! cmdblock) { - cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (sizeof (*cmdblock)); + cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (state, + sizeof (*cmdblock)); cmdblock->cmd.exec = grub_script_execute_cmdblock; cmdblock->cmd.next = 0; cmdblock->cmdlist = cmd; @@ -289,31 +294,53 @@ struct grub_script * grub_script_parse (char *script, grub_err_t (*getline) (char **)) { struct grub_script *parsed; + struct grub_script_mem *memfree; struct grub_script_mem *membackup; + struct grub_lexer_param *lexstate; + struct grub_parser_param *parsestate; parsed = grub_malloc (sizeof (*parsed)); if (! parsed) return 0; + parsestate = grub_malloc (sizeof (*parsestate)); + if (! parsestate) + return 0; + + parsestate->err = 0; + parsestate->func_mem = 0; + parsestate->memused = 0; + parsestate->parsed = 0; + /* Initialize the lexer. */ - grub_script_lexer_init (script, getline); - - grub_script_parsed = 0; - - membackup = grub_script_mem_record (); - - /* Parse the script, the result is stored in - `grub_script_parsed'. */ - if (grub_script_yyparse () || ! grub_script_parsed) + lexstate = grub_script_lexer_init (script, getline); + if (! lexstate) { - struct grub_script_mem *memfree; - memfree = grub_script_mem_record_stop (membackup); - grub_script_mem_free (memfree); + grub_free (parsed); + grub_free (parsestate); return 0; } - parsed->mem = grub_script_mem_record_stop (membackup); - parsed->cmd = grub_script_parsed; + parsestate->lexerstate = lexstate; + + membackup = grub_script_mem_record (parsestate); + + /* Parse the script. */ + if (grub_script_yyparse (parsestate) || parsestate->err) + { + struct grub_script_mem *memfree; + memfree = grub_script_mem_record_stop (parsestate, membackup); + grub_script_mem_free (memfree); + grub_free (lexstate); + grub_free (parsestate); + return 0; + } + + parsed->mem = grub_script_mem_record_stop (parsestate, membackup); + parsed->cmd = parsestate->parsed; + + grub_free (lexstate); + grub_free (parsestate); return parsed; }