2006-17-04 Marco Gerards <marco@gnu.org>

* include/grub/script.h: Include <grub/parser.h> 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.
This commit is contained in:
marco_g 2006-04-17 13:01:20 +00:00
parent 6de2ee9903
commit bfa2bd9efb
5 changed files with 369 additions and 197 deletions

View file

@ -1,3 +1,82 @@
2006-17-04 Marco Gerards <marco@gnu.org>
* include/grub/script.h: Include <grub/parser.h> 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 <marco@gnu.org> 2006-16-04 Marco Gerards <marco@gnu.org>
* normal/command.c (grub_command_init): Remove the title command. * normal/command.c (grub_command_init): Remove the title command.

View file

@ -23,6 +23,8 @@
#include <grub/types.h> #include <grub/types.h>
#include <grub/err.h> #include <grub/err.h>
#include <grub/parser.h>
#include "grub_script.tab.h"
struct grub_script_mem; struct grub_script_mem;
@ -123,33 +125,98 @@ struct grub_script_cmd_menuentry
int options; int options;
}; };
struct grub_script_arglist * /* State of the lexer as passed to the lexer. */
grub_script_create_arglist (void); 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 * 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_arg *arg);
struct grub_script_cmd * 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_arglist *arglist);
struct grub_script_cmd * struct grub_script_cmd *
grub_script_create_cmdblock (void); grub_script_create_cmdblock (struct grub_parser_param *state);
struct grub_script_cmd * 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 *true,
struct grub_script_cmd *false); struct grub_script_cmd *false);
struct grub_script_cmd * 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, char *sourcecode,
int options); int options);
struct grub_script_cmd * 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_cmd *cmd);
struct grub_script_arg * 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); grub_script_arg_type_t type, char *str);
struct grub_script *grub_script_parse (char *script, 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 *grub_script_create (struct grub_script_cmd *cmd,
struct grub_script_mem *mem); struct grub_script_mem *mem);
void grub_script_lexer_init (char *s, grub_err_t (*getline) (char **)); struct grub_lexer_param *grub_script_lexer_init (char *s,
void grub_script_lexer_ref (void); grub_err_t (*getline) (char **));
void grub_script_lexer_deref (void); void grub_script_lexer_ref (struct grub_lexer_param *);
void grub_script_lexer_record_start (void); void grub_script_lexer_deref (struct grub_lexer_param *);
char *grub_script_lexer_record_stop (void); 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. */ /* Functions to track allocated memory. */
void *grub_script_malloc (grub_size_t size); struct grub_script_mem *grub_script_mem_record (struct grub_parser_param *state);
struct grub_script_mem *grub_script_mem_record (void); struct grub_script_mem *grub_script_mem_record_stop (struct grub_parser_param *state,
struct grub_script_mem *grub_script_mem_record_stop (struct grub_script_mem *restore); struct grub_script_mem *restore);
void *grub_script_malloc (struct grub_parser_param *state, grub_size_t size);
/* Functions used by bison. */ /* Functions used by bison. */
int grub_script_yylex (void); int grub_script_yylex (YYSTYPE *, struct grub_parser_param *);
int grub_script_yyparse (void); int grub_script_yyparse (struct grub_parser_param *);
void grub_script_yyerror (char const *err); void grub_script_yyerror (struct grub_parser_param *, char const *);
/* Commands to execute, don't use these directly. */ /* Commands to execute, don't use these directly. */
grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd);

View file

@ -25,10 +25,6 @@
#include "grub_script.tab.h" #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 static int
check_varstate (grub_parser_state_t state) check_varstate (grub_parser_state_t state)
{ {
@ -48,109 +44,109 @@ check_textstate (grub_parser_state_t state)
|| state == GRUB_PARSER_STATE_DQUOTE); || state == GRUB_PARSER_STATE_DQUOTE);
} }
/* The amount of references to the lexer by the parser. If the parser struct grub_lexer_param *
expects tokens the lexer is referenced. */ grub_script_lexer_init (char *script, grub_err_t (*getline) (char **))
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 **))
{ {
grub_script_lexer_state = GRUB_PARSER_STATE_TEXT; struct grub_lexer_param *param;
grub_script_lexer_getline = getline;
grub_script_lexer_refs = 0; param = grub_malloc (sizeof (*param));
grub_script_lexer_done = 0; if (! param)
newscript = 0; return 0;
script = s;
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 void
grub_script_lexer_ref (void) grub_script_lexer_ref (struct grub_lexer_param *state)
{ {
grub_script_lexer_refs++; state->refs++;
} }
void 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. */ /* Start recording all characters passing through the lexer. */
void void
grub_script_lexer_record_start (void) grub_script_lexer_record_start (struct grub_lexer_param *state)
{ {
record = 1; state->record = 1;
recordlen = 100; state->recordlen = 100;
recording = grub_malloc (recordlen); state->recording = grub_malloc (state->recordlen);
recordpos = 0; state->recordpos = 0;
} }
char * 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 `}'. */ /* 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"); grub_printf ("Internal error while parsing menu entry");
for (;;); /* XXX */ 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 /* When recording is enabled, record the character C as the next item
in the character stream. */ in the character stream. */
static void static void
recordchar (char c) recordchar (struct grub_lexer_param *state, char c)
{ {
if (recordpos == recordlen) if (state->recordpos == state->recordlen)
{ {
char *old = recording; char *old = state->recording;
recordlen += 100; state->recordlen += 100;
recording = grub_realloc (recording, recordlen); state->recording = grub_realloc (state->recording, state->recordlen);
if (! recording) if (! state->recording)
{ {
grub_free (old); grub_free (old);
record = 0; state->record = 0;
} }
} }
recording[recordpos++] = c; state->recording[state->recordpos++] = c;
} }
/* Fetch the next character for the lexer. */ /* Fetch the next character for the lexer. */
static void static void
nextchar (void) nextchar (struct grub_lexer_param *state)
{ {
if (record) if (state->record)
recordchar (*script); recordchar (state, *state->script);
script++; state->script++;
} }
int int
grub_script_yylex2 (void); grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate);
int int
grub_script_yylex (void) grub_script_yylex (YYSTYPE *yylval, struct grub_parser_param *parsestate)
{ {
int r = -1; int r = -1;
while (r == -1) while (r == -1)
{ {
r = grub_script_yylex2 (); r = grub_script_yylex2 (yylval, parsestate);
if (r == ' ' || r == '\n') if (r == ' ' || r == '\n')
r = -1; r = -1;
} }
@ -158,48 +154,49 @@ grub_script_yylex (void)
} }
int int
grub_script_yylex2 (void) grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate)
{ {
grub_parser_state_t newstate; grub_parser_state_t newstate;
char use; char use;
char *buffer; char *buffer;
char *bp; char *bp;
struct grub_lexer_param *state = parsestate->lexerstate;
if (grub_script_lexer_done) if (state->done)
return 0; return 0;
if (! *script) if (! *state->script)
{ {
/* Check if more tokens are requested by the parser. */ /* Check if more tokens are requested by the parser. */
if ((grub_script_lexer_refs if ((state->refs
|| grub_script_lexer_state == GRUB_PARSER_STATE_ESC) || state->state == GRUB_PARSER_STATE_ESC)
&& grub_script_lexer_getline) && state->getline)
{ {
while (!script || ! grub_strlen (script)) while (!state->script || ! grub_strlen (state->script))
{ {
grub_free (newscript); grub_free (state->newscript);
newscript = 0; state->newscript = 0;
grub_script_lexer_getline (&newscript); state->getline (&state->newscript);
script = newscript; state->script = state->newscript;
if (! script) if (! state->script)
return 0; return 0;
} }
grub_dprintf ("scripting", "token=`\\n'\n"); grub_dprintf ("scripting", "token=`\\n'\n");
recordchar ('\n'); recordchar (state, '\n');
if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC) if (state->state != GRUB_PARSER_STATE_ESC)
return '\n'; return '\n';
} }
else else
{ {
grub_free (newscript); grub_free (state->newscript);
newscript = 0; state->newscript = 0;
grub_script_lexer_done = 1; state->done = 1;
grub_dprintf ("scripting", "token=`\\n'\n"); grub_dprintf ("scripting", "token=`\\n'\n");
return '\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. */ /* Check if it is a text. */
if (check_textstate (newstate)) if (check_textstate (newstate))
@ -208,21 +205,21 @@ grub_script_yylex2 (void)
length symbol. */ length symbol. */
if (newstate == GRUB_PARSER_STATE_TEXT) if (newstate == GRUB_PARSER_STATE_TEXT)
{ {
switch (*script) switch (*state->script)
{ {
case ' ': case ' ':
while (*script) while (*state->script)
{ {
newstate = grub_parser_cmdline_state (grub_script_lexer_state, newstate = grub_parser_cmdline_state (state->state,
*script, &use); *state->script, &use);
if (! (grub_script_lexer_state == GRUB_PARSER_STATE_TEXT if (! (state->state == GRUB_PARSER_STATE_TEXT
&& *script == ' ')) && *state->script == ' '))
{ {
grub_dprintf ("scripting", "token=` '\n"); grub_dprintf ("scripting", "token=` '\n");
return ' '; return ' ';
} }
grub_script_lexer_state = newstate; state->state = newstate;
nextchar (); nextchar (state);
} }
grub_dprintf ("scripting", "token=` '\n"); grub_dprintf ("scripting", "token=` '\n");
return ' '; return ' ';
@ -232,26 +229,26 @@ grub_script_yylex2 (void)
case '\n': case '\n':
{ {
char c; char c;
grub_dprintf ("scripting", "token=`%c'\n", *script); grub_dprintf ("scripting", "token=`%c'\n", *state->script);
c = *script;; c = *state->script;;
nextchar (); nextchar (state);
return c; return c;
} }
} }
} }
/* XXX: Use a better size. */ /* XXX: Use a better size. */
buffer = grub_script_malloc (2048); buffer = grub_script_malloc (parsestate, 2048);
if (! buffer) if (! buffer)
return 0; return 0;
bp = buffer; bp = buffer;
/* Read one token, possible quoted. */ /* Read one token, possible quoted. */
while (*script) while (*state->script)
{ {
newstate = grub_parser_cmdline_state (grub_script_lexer_state, newstate = grub_parser_cmdline_state (state->state,
*script, &use); *state->script, &use);
/* Check if a variable name starts. */ /* Check if a variable name starts. */
if (check_varstate (newstate)) if (check_varstate (newstate))
@ -261,7 +258,7 @@ grub_script_yylex2 (void)
when a special token was found. It will be recognised when a special token was found. It will be recognised
next time when this function is called. */ next time when this function is called. */
if (newstate == GRUB_PARSER_STATE_TEXT if (newstate == GRUB_PARSER_STATE_TEXT
&& grub_script_lexer_state != GRUB_PARSER_STATE_ESC) && state->state != GRUB_PARSER_STATE_ESC)
{ {
int breakout = 0; int breakout = 0;
@ -281,14 +278,14 @@ grub_script_yylex2 (void)
else if (use) else if (use)
*(bp++) = use; *(bp++) = use;
grub_script_lexer_state = newstate; state->state = newstate;
nextchar (); nextchar (state);
} }
/* A string of text was read in. */ /* A string of text was read in. */
*bp = '\0'; *bp = '\0';
grub_dprintf ("scripting", "token=`%s'\n", buffer); grub_dprintf ("scripting", "token=`%s'\n", buffer);
grub_script_yylval.string = buffer; yylval->string = buffer;
/* Detect some special tokens. */ /* Detect some special tokens. */
if (! grub_strcmp (buffer, "while")) if (! grub_strcmp (buffer, "while"))
@ -314,38 +311,38 @@ grub_script_yylex2 (void)
|| newstate == GRUB_PARSER_STATE_QVAR) || newstate == GRUB_PARSER_STATE_QVAR)
{ {
/* XXX: Use a better size. */ /* XXX: Use a better size. */
buffer = grub_script_malloc (2096); buffer = grub_script_malloc (parsestate, 2096);
if (! buffer) if (! buffer)
return 0; return 0;
bp = buffer; bp = buffer;
/* This is a variable, read the variable name. */ /* This is a variable, read the variable name. */
while (*script) while (*state->script)
{ {
newstate = grub_parser_cmdline_state (grub_script_lexer_state, newstate = grub_parser_cmdline_state (state->state,
*script, &use); *state->script, &use);
/* Check if this character is not part of the variable name /* Check if this character is not part of the variable name
anymore. */ anymore. */
if (! (check_varstate (newstate))) if (! (check_varstate (newstate)))
{ {
if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2 if (state->state == GRUB_PARSER_STATE_VARNAME2
|| grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2) || state->state == GRUB_PARSER_STATE_QVARNAME2)
nextchar (); nextchar (state);
grub_script_lexer_state = newstate; state->state = newstate;
break; break;
} }
if (use) if (use)
*(bp++) = use; *(bp++) = use;
nextchar (); nextchar (state);
grub_script_lexer_state = newstate; state->state = newstate;
} }
*bp = '\0'; *bp = '\0';
grub_script_lexer_state = newstate; state->state = newstate;
grub_script_yylval.string = buffer; yylval->string = buffer;
grub_dprintf ("scripting", "vartoken=`%s'\n", buffer); grub_dprintf ("scripting", "vartoken=`%s'\n", buffer);
return GRUB_PARSER_TOKEN_VAR; return GRUB_PARSER_TOKEN_VAR;
@ -360,7 +357,7 @@ grub_script_yylex2 (void)
} }
void void
grub_script_yyerror (char const *err) grub_script_yyerror (struct grub_parser_param *lex, char const *err)
{ {
grub_printf ("%s\n", err); grub_printf ("%s\n", err);
} }

View file

@ -25,12 +25,6 @@
#define YYFREE grub_free #define YYFREE grub_free
#define YYMALLOC grub_malloc #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 <string> "if" "while" "function" "else" "then" "fi" %type <string> "if" "while" "function" "else" "then" "fi"
%type <string> text GRUB_PARSER_TOKEN_NAME GRUB_PARSER_TOKEN_VAR %type <string> 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... */ /* 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'. */ for example: `foo${bar}baz'. */
argument: GRUB_PARSER_TOKEN_VAR 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 | 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 /* XXX: Currently disabled to simplify the parser. This should be
parsed by yet another parser for readibility. */ parsed by yet another parser for readibility. */
@ -104,21 +102,21 @@ argument: GRUB_PARSER_TOKEN_VAR
arguments: argument arguments: argument
{ {
$$ = grub_script_add_arglist (0, $1); $$ = grub_script_add_arglist (state, 0, $1);
} }
| arguments argument | arguments argument
{ {
$$ = grub_script_add_arglist ($1, $2); $$ = grub_script_add_arglist (state, $1, $2);
} }
; ;
grubcmd: GRUB_PARSER_TOKEN_NAME arguments grubcmd: GRUB_PARSER_TOKEN_NAME arguments
{ {
$$ = grub_script_create_cmdline ($1, $2); $$ = grub_script_create_cmdline (state, $1, $2);
} }
| GRUB_PARSER_TOKEN_NAME | 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. */ /* A block of commands. */
commands: command commands: command
{ {
$$ = grub_script_add_cmd (0, $1); $$ = grub_script_add_cmd (state, 0, $1);
} }
| command ';' commands | command ';' commands
{ {
struct grub_script_cmdblock *cmd; struct grub_script_cmdblock *cmd;
cmd = (struct grub_script_cmdblock *) $1; cmd = (struct grub_script_cmdblock *) $1;
$$ = grub_script_add_cmd (cmd, $3); $$ = grub_script_add_cmd (state, cmd, $3);
} }
| error | error
{ {
yyerror ("Incorrect command"); yyerror (state, "Incorrect command");
err = 1; state->err = 1;
yyerrok; yyerrok;
} }
; ;
@ -151,59 +149,61 @@ commands: command
/* A function. Carefully save the memory that is allocated. */ /* A function. Carefully save the memory that is allocated. */
function: "function" GRUB_PARSER_TOKEN_NAME function: "function" GRUB_PARSER_TOKEN_NAME
{ {
grub_script_lexer_ref (); grub_script_lexer_ref (state->lexerstate);
} '{' } '{'
{ {
/* The first part of the function was recognised. /* The first part of the function was recognised.
Now start recording the memory usage to store Now start recording the memory usage to store
this function. */ this function. */
func_mem = grub_script_mem_record (); state->func_mem = grub_script_mem_record (state);
} commands '}' } commands '}'
{ {
struct grub_script *script; struct grub_script *script;
/* All the memory usage for parsing this function /* All the memory usage for parsing this function
was recorded. */ was recorded. */
func_mem = grub_script_mem_record_stop (func_mem); state->func_mem = grub_script_mem_record_stop (state,
script = grub_script_create ($6, func_mem); state->func_mem);
script = grub_script_create ($6, state->func_mem);
if (script) if (script)
grub_script_function_create ($2, 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. */ /* A menu entry. Carefully save the memory that is allocated. */
menuentry: "menuentry" argument menuentry: "menuentry" argument
{ {
grub_script_lexer_ref (); grub_script_lexer_ref (state->lexerstate);
} '{' } '{'
{ {
/* Record sourcecode of the menu entry. It can be /* Record sourcecode of the menu entry. It can be
parsed multiple times if it is part of a parsed multiple times if it is part of a
loop. */ loop. */
grub_script_lexer_record_start (); grub_script_lexer_record_start (state->lexerstate);
} commands '}' } commands '}'
{ {
menu_entry = grub_script_lexer_record_stop (); char *menu_entry;
$$ = grub_script_create_cmdmenu ($2, menu_entry, 0); menu_entry = grub_script_lexer_record_stop (state->lexerstate);
grub_script_lexer_deref (); $$ = 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 /* The first part of the if statement. It's used to switch the lexer
to a state in which it demands more tokens. */ 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. */ /* The if statement. */
if: if_statement grubcmd ';' "then" commands "fi" if: if_statement grubcmd ';' "then" commands "fi"
{ {
$$ = grub_script_create_cmdif ($2, $5, 0); $$ = grub_script_create_cmdif (state, $2, $5, 0);
grub_script_lexer_deref (); grub_script_lexer_deref (state->lexerstate);
} }
| if_statement grubcmd ';' "then" commands "else" commands "fi" | if_statement grubcmd ';' "then" commands "else" commands "fi"
{ {
$$ = grub_script_create_cmdif ($2, $5, $7); $$ = grub_script_create_cmdif (state, $2, $5, $7);
grub_script_lexer_deref (); grub_script_lexer_deref (state->lexerstate);
} }
; ;

View file

@ -28,11 +28,7 @@
allocations. The memory is free'ed in case of an error, or allocations. The memory is free'ed in case of an error, or
assigned to the parsed script when parsing was successful. */ assigned to the parsed script when parsing was successful. */
/* The memory that was used while parsing and scanning. */ /* XXX */
static struct grub_script_mem *grub_script_memused;
/* The result of the parser. */
struct grub_script_cmd *grub_script_parsed = 0;
/* In case of the normal malloc, some additional bytes are allocated /* In case of the normal malloc, some additional bytes are allocated
for this datastructure. All reserved memory is stored in a linked 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. */ /* Return malloc'ed memory and keep track of the allocation. */
void * 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; struct grub_script_mem *mem;
mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem) mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem)
- sizeof (char)); - sizeof (char));
grub_dprintf ("scripting", "malloc %p\n", mem); grub_dprintf ("scripting", "malloc %p\n", mem);
mem->next = grub_script_memused; mem->next = state->memused;
grub_script_memused = mem; state->memused = mem;
return (void *) &mem->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 /* Start recording memory usage. Returns the memory that should be
restored when calling stop. */ restored when calling stop. */
struct grub_script_mem * 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; struct grub_script_mem *mem = state->memused;
grub_script_memused = 0; state->memused = 0;
return mem; return mem;
} }
/* Stop recording memory usage. Restore previous recordings using /* Stop recording memory usage. Restore previous recordings using
RESTORE. Return the recorded memory. */ RESTORE. Return the recorded memory. */
struct grub_script_mem * 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; struct grub_script_mem *mem = state->memused;
grub_script_memused = restore; state->memused = restore;
return mem; 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 /* Extend the argument arg with a variable or string of text. If ARG
is zero a new list is created. */ is zero a new list is created. */
struct grub_script_arg * 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) grub_script_arg_type_t type, char *str)
{ {
struct grub_script_arg *argpart; struct grub_script_arg *argpart;
struct grub_script_arg *ll; 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->type = type;
argpart->str = str; argpart->str = str;
argpart->next = 0; 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 /* Add the argument ARG to the end of the argument list LIST. If LIST
is zero, a new list will be created. */ is zero, a new list will be created. */
struct grub_script_arglist * 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 *link;
struct grub_script_arglist *ll; struct grub_script_arglist *ll;
grub_dprintf ("scripting", "arglist\n"); 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->next = 0;
link->arg = arg; link->arg = arg;
link->argcount = 0; 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 contains the name of the command that should be executed. ARGLIST
holds all arguments for this command. */ holds all arguments for this command. */
struct grub_script_cmd * 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; struct grub_script_cmdline *cmd;
grub_dprintf ("scripting", "cmdline\n"); 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.exec = grub_script_execute_cmdline;
cmd->cmd.next = 0; cmd->cmd.next = 0;
cmd->arglist = arglist; 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 interpreter will run the command TRUE, otherwise the interpreter
runs the command FALSE. */ runs the command FALSE. */
struct grub_script_cmd * 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 *true,
struct grub_script_cmd *false) struct grub_script_cmd *false)
{ {
@ -190,7 +191,7 @@ grub_script_create_cmdif (struct grub_script_cmd *bool,
grub_dprintf ("scripting", "cmdif\n"); 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.exec = grub_script_execute_cmdif;
cmd->cmd.next = 0; cmd->cmd.next = 0;
cmd->bool = bool; 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 title. The sourcecode for this entry is passed in SOURCECODE.
The options for this entry are passed in OPTIONS. */ The options for this entry are passed in OPTIONS. */
struct grub_script_cmd * 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, char *sourcecode,
int options) int options)
{ {
@ -221,7 +223,7 @@ grub_script_create_cmdmenu (struct grub_script_arg *title,
sourcecode[i] = '\0'; 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.exec = grub_script_execute_menuentry;
cmd->cmd.next = 0; cmd->cmd.next = 0;
cmd->sourcecode = sourcecode; 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 be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new
cmdblock will be created. */ cmdblock will be created. */
struct grub_script_cmd * 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"); grub_dprintf ("scripting", "cmdblock\n");
@ -244,7 +248,8 @@ grub_script_add_cmd (struct grub_script_cmdblock *cmdblock, struct grub_script_c
if (! cmdblock) 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.exec = grub_script_execute_cmdblock;
cmdblock->cmd.next = 0; cmdblock->cmd.next = 0;
cmdblock->cmdlist = cmd; cmdblock->cmdlist = cmd;
@ -289,31 +294,53 @@ struct grub_script *
grub_script_parse (char *script, grub_err_t (*getline) (char **)) grub_script_parse (char *script, grub_err_t (*getline) (char **))
{ {
struct grub_script *parsed; struct grub_script *parsed;
struct grub_script_mem *memfree;
struct grub_script_mem *membackup; struct grub_script_mem *membackup;
struct grub_lexer_param *lexstate;
struct grub_parser_param *parsestate;
parsed = grub_malloc (sizeof (*parsed)); parsed = grub_malloc (sizeof (*parsed));
if (! parsed) if (! parsed)
return 0; 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. */ /* Initialize the lexer. */
grub_script_lexer_init (script, getline); lexstate = grub_script_lexer_init (script, getline);
if (! lexstate)
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)
{ {
struct grub_script_mem *memfree; grub_free (parsed);
memfree = grub_script_mem_record_stop (membackup); grub_free (parsestate);
grub_script_mem_free (memfree);
return 0; return 0;
} }
parsed->mem = grub_script_mem_record_stop (membackup); parsestate->lexerstate = lexstate;
parsed->cmd = grub_script_parsed;
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; return parsed;
} }