%{
/* yylex.l The scripting lexer. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009,2010 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/script_sh.h>
#include "grub_script.tab.h"
#define yyfree grub_lexer_yyfree
#define yyalloc grub_lexer_yyalloc
#define yyrealloc grub_lexer_yyrealloc
/*
* As we don't have access to yyscanner, we cannot do much except to
* print the fatal error.
*/
#define YY_FATAL_ERROR(msg) \
do { \
} while (0)
do { \
} while (0)
#define RECORD \
do { \
} while (0)
#define ARG(t) \
do { \
return GRUB_PARSER_TOKEN_WORD; \
} while (0)
/* We don't need YY_INPUT, as we rely on yy_scan_strings */
/* forward declarations */
static void copy_string (struct grub_parser_param *, const char *,
unsigned hint);
%}
%top{
#include <config.h>
#define YY_TYPEDEF_YY_SIZE_T 1
/*
* Some flex hacks for -nostdinc; XXX We need to fix these when libc
* support becomes availble in GRUB.
*/
#ifndef GRUB_UTIL
#define stdin 0
#define stdout 0
#define fprintf(...) 0
#define exit(...)
#endif
}
/* Reduce lexer size, by not defining these. */
BLANK [ \t]
COMMENT #.*$
CHAR [^{}|&$;<> \t\n\'\"\\]
DIGITS [[:digit:]]+
NAME [[:alpha:]_][[:alnum:]_]*
ESC \\(.|\n)
SQCHR [^\']
DQCHR {ESC}|[^\\\"]
DQSTR \"{DQCHR}*\"
SQSTR \'{SQCHR}*\'
SPECIAL \?|\#|\*|\@
VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+
MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n))
%x SPLIT
%x DQUOTE
%x SQUOTE
%x VAR
%%
/* White spaces */
{BLANK}+ { RECORD; }
{COMMENT} { RECORD; }
/* Special symbols */
"\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
"||" { RECORD; return GRUB_PARSER_TOKEN_OR; }
"&&" { RECORD; return GRUB_PARSER_TOKEN_AND; }
";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; }
"|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; }
"&" { RECORD; return GRUB_PARSER_TOKEN_AMP; }
";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; }
"<" { RECORD; return GRUB_PARSER_TOKEN_LT; }
">" { RECORD; return GRUB_PARSER_TOKEN_GT; }
/* Reserved words */
"{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
"}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
"[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
"]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
"case" { RECORD; return GRUB_PARSER_TOKEN_CASE; }
"do" { RECORD; return GRUB_PARSER_TOKEN_DO; }
"done" { RECORD; return GRUB_PARSER_TOKEN_DONE; }
"elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; }
"else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; }
"esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; }
"fi" { RECORD; return GRUB_PARSER_TOKEN_FI; }
"for" { RECORD; return GRUB_PARSER_TOKEN_FOR; }
"if" { RECORD; return GRUB_PARSER_TOKEN_IF; }
"in" { RECORD; return GRUB_PARSER_TOKEN_IN; }
"select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; }
"then" { RECORD; return GRUB_PARSER_TOKEN_THEN; }
"until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; }
"while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; }
"function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; }
{MULTILINE} {
if (grub_lexer_unput (yytext, yyscanner))
return GRUB_PARSER_TOKEN_BAD;
}
{NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
{WORD} {
RECORD;
yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
if (grub_lexer_resplit (yytext, yyscanner))
{
yypop_buffer_state (yyscanner);
return GRUB_PARSER_TOKEN_WORD;
}
yyextra->lexerstate->resplit = 1;
}
. {
grub_script_yyerror (yyextra, yytext);
return GRUB_PARSER_TOKEN_BAD;
}
/* Split word into multiple args */
<SPLIT>{
\\. { COPY (yytext + 1, yyleng - 1); }
\\\n { /* ignore */ }
\" {
yy_push_state (DQUOTE, yyscanner);
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
\' {
yy_push_state (SQUOTE, yyscanner);
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
\$ {
yy_push_state (VAR, yyscanner);
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
\\ |
[^\"\'\$\\]+ { COPY (yytext, yyleng); }
<<EOF>> {
yy_pop_state (yyscanner);
yypop_buffer_state (yyscanner);
yyextra->lexerstate->resplit = 0;
yyextra->lexerstate->merge_end = 1;
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
}
<VAR>{
{SPECIAL} |
{DIGITS} |
{NAME} {
COPY (yytext, yyleng);
yy_pop_state (yyscanner);
if (YY_START == SPLIT)
ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
else
ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
}
\{{SPECIAL}\} |
\{{DIGITS}\} |
\{{NAME}\} {
yytext[yyleng - 1] = '\0';
COPY (yytext + 1, yyleng - 2);
yy_pop_state (yyscanner);
if (YY_START == SPLIT)
ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
else
ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
}
.|\n { return GRUB_PARSER_TOKEN_BAD; }
}
<SQUOTE>{
\' {
yy_pop_state (yyscanner);
ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
}
[^\']+ { COPY (yytext, yyleng); }
}
<DQUOTE>{
\\\$ { COPY ("$", 1); }
\\\\ { COPY ("\\", 1); }
\\\" { COPY ("\"", 1); }
\\\n { /* ignore */ }
[^\"\$\\\n]+ { COPY (yytext, yyleng); }
\" {
yy_pop_state (yyscanner);
ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
}
\$ {
yy_push_state (VAR, yyscanner);
ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
}
(.|\n) { COPY (yytext, yyleng); }
}
<<EOF>> {
yypop_buffer_state (yyscanner);
yyextra->lexerstate->eof = 1;
return GRUB_PARSER_TOKEN_EOF;
}
%%
int
yywrap (yyscan_t yyscanner)
{
if (yyget_extra (yyscanner)->lexerstate->resplit)
return 1;
return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
}
static void
grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused)))
{
grub_free(ptr);
}
static void*
grub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused)))
{
return grub_malloc (size);
}
static void*
grub_lexer_yyrealloc (void *ptr, yy_size_t size,
yyscan_t yyscanner __attribute__ ((unused)))
{
return grub_realloc (ptr, size);
}
static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
{
grub_size_t size;
char *ptr;
unsigned len;
len = hint ? hint : grub_strlen (str);
if (parser->lexerstate->used + len >= parser->lexerstate->size)
{
size = len * 2;
if (size < parser->lexerstate->size * 2)
size = parser->lexerstate->size * 2;
ptr = grub_realloc (parser->lexerstate->text, size);
if (!ptr)
{
grub_script_yyerror (parser, 0);
return;
}
parser->lexerstate->text = ptr;
parser->lexerstate->size = size;
}
grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
parser->lexerstate->used += len;
}
static int
grub_lexer_resplit (const char *text, yyscan_t yyscanner)
{
/* resplit text */
if (yy_scan_string (text, yyscanner))
{
yyget_extra (yyscanner)->lexerstate->merge_start = 1;
yy_push_state (SPLIT, yyscanner);
return 0;
}
grub_script_yyerror (yyget_extra (yyscanner), 0);
return 1;
}
static int
grub_lexer_unput (const char *text, yyscan_t yyscanner)
{
struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
grub_free (lexerstate->prefix);
lexerstate->prefix = grub_strdup (text);
if (! lexerstate->prefix)
{
grub_script_yyerror (yyget_extra (yyscanner), "out of memory");
return 1;
}
return 0;
}