1
/* lexer.c - The scripting lexer. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2005 Free Software Foundation, Inc.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
#include <grub/parser.h>
22
#include <grub/misc.h>
24
#include <grub/script.h>
26
#include "grub_script.tab.h"
28
static grub_parser_state_t grub_script_lexer_state;
29
static int grub_script_lexer_done = 0;
30
static grub_err_t (*grub_script_lexer_getline) (char **);
33
check_varstate (grub_parser_state_t state)
35
return (state == GRUB_PARSER_STATE_VARNAME
36
|| state == GRUB_PARSER_STATE_VAR
37
|| state == GRUB_PARSER_STATE_QVAR
38
|| state == GRUB_PARSER_STATE_VARNAME2
39
|| state == GRUB_PARSER_STATE_QVARNAME
40
|| state == GRUB_PARSER_STATE_QVARNAME2);
44
check_textstate (grub_parser_state_t state)
46
return (state == GRUB_PARSER_STATE_TEXT
47
|| state == GRUB_PARSER_STATE_QUOTE
48
|| state == GRUB_PARSER_STATE_DQUOTE);
51
/* The amount of references to the lexer by the parser. If the parser
52
expects tokens the lexer is referenced. */
53
static int grub_script_lexer_refs = 0;
55
static char *newscript;
57
/* XXX: The lexer is not reentrant. */
59
grub_script_lexer_init (char *s, grub_err_t (*getline) (char **))
61
grub_script_lexer_state = GRUB_PARSER_STATE_TEXT;
62
grub_script_lexer_getline = getline;
63
grub_script_lexer_refs = 0;
64
grub_script_lexer_done = 0;
70
grub_script_lexer_ref (void)
72
grub_script_lexer_refs++;
76
grub_script_lexer_deref (void)
78
grub_script_lexer_refs--;
82
grub_script_yylex (void)
84
grub_parser_state_t newstate;
89
if (grub_script_lexer_done)
94
/* Check if more tokens are requested by the parser. */
95
if ((grub_script_lexer_refs
96
|| grub_script_lexer_state == GRUB_PARSER_STATE_ESC)
97
&& grub_script_lexer_getline)
99
while (! grub_strlen (script))
101
grub_free (newscript);
102
grub_script_lexer_getline (&newscript);
105
grub_dprintf ("scripting", "token=`\\n'\n");
106
if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC)
111
grub_free (newscript);
113
grub_script_lexer_done = 1;
114
grub_dprintf ("scripting", "token=`\\n'\n");
119
newstate = grub_parser_cmdline_state (grub_script_lexer_state, *script, &use);
121
/* Check if it is a text. */
122
if (check_textstate (newstate))
124
/* In case the string is not quoted, this can be a one char
126
if (newstate == GRUB_PARSER_STATE_TEXT)
133
newstate = grub_parser_cmdline_state (grub_script_lexer_state,
135
if (! (grub_script_lexer_state == GRUB_PARSER_STATE_TEXT
138
grub_dprintf ("scripting", "token=` '\n");
141
grub_script_lexer_state = newstate;
144
grub_dprintf ("scripting", "token=` '\n");
150
grub_dprintf ("scripting", "token=`%c'\n", *script);
155
/* XXX: Use a better size. */
156
buffer = grub_script_malloc (2096);
162
/* Read one token, possible quoted. */
165
newstate = grub_parser_cmdline_state (grub_script_lexer_state,
168
/* Check if a variable name starts. */
169
if (check_varstate (newstate))
172
/* If the string is not quoted or escaped, stop processing
173
when a special token was found. It will be recognised
174
next time when this function is called. */
175
if (newstate == GRUB_PARSER_STATE_TEXT
176
&& grub_script_lexer_state != GRUB_PARSER_STATE_ESC)
196
grub_script_lexer_state = newstate;
200
/* A string of text was read in. */
202
grub_dprintf ("scripting", "token=`%s'\n", buffer);
203
grub_script_yylval.string = buffer;
205
/* Detect some special tokens. */
206
if (! grub_strcmp (buffer, "while"))
207
return GRUB_PARSER_TOKEN_WHILE;
208
else if (! grub_strcmp (buffer, "if"))
209
return GRUB_PARSER_TOKEN_IF;
210
else if (! grub_strcmp (buffer, "function"))
211
return GRUB_PARSER_TOKEN_FUNCTION;
212
else if (! grub_strcmp (buffer, "else"))
213
return GRUB_PARSER_TOKEN_ELSE;
214
else if (! grub_strcmp (buffer, "then"))
215
return GRUB_PARSER_TOKEN_THEN;
216
else if (! grub_strcmp (buffer, "fi"))
217
return GRUB_PARSER_TOKEN_FI;
219
return GRUB_PARSER_TOKEN_NAME;
221
else if (newstate == GRUB_PARSER_STATE_VAR
222
|| newstate == GRUB_PARSER_STATE_QVAR)
224
/* XXX: Use a better size. */
225
buffer = grub_script_malloc (2096);
231
/* This is a variable, read the variable name. */
234
newstate = grub_parser_cmdline_state (grub_script_lexer_state,
237
/* Check if this character is not part of the variable name
239
if (! (check_varstate (newstate)))
241
if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2
242
|| grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2)
244
grub_script_lexer_state = newstate;
251
grub_script_lexer_state = newstate;
255
grub_script_lexer_state = newstate;
256
grub_script_yylval.string = buffer;
257
grub_dprintf ("scripting", "vartoken=`%s'\n", buffer);
259
return GRUB_PARSER_TOKEN_VAR;
263
/* There is either text or a variable name. In the case you
264
arrive here there is a serious problem with the lexer. */
265
grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n");
271
grub_script_yyerror (char const *err)