grub/script/yylex.l

366 lines
11 KiB
Text
Raw Normal View History

2010-01-22 13:37:27 +00:00
%{
/* yylex.l The scripting lexer. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* 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/parser.h>
#include <grub/misc.h>
#include <grub/mm.h>
#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 { \
grub_printf ("fatal error: %s\n", msg); \
} while (0)
2010-01-22 18:44:00 +00:00
#define COPY(str, hint) \
do { \
copy_string (yyextra, str, hint); \
2010-01-22 13:37:27 +00:00
} while (0)
2010-01-22 18:44:00 +00:00
#define RECORD \
do { \
grub_script_lexer_record (yyextra, yytext); \
2010-01-22 13:37:27 +00:00
} while (0)
2010-01-22 18:44:00 +00:00
#define ARG(t) \
do { \
2010-01-22 13:37:27 +00:00
yyextra->lexerstate->type = t; \
return GRUB_PARSER_TOKEN_WORD; \
} while (0)
/* We don't need YY_INPUT, as we rely on yy_scan_strings */
#define YY_INPUT(buf,res,max) do { res = 0; } while (0)
/* forward declarations */
2010-06-12 05:36:02 +00:00
static int grub_lexer_unput (const char *input, yyscan_t yyscanner);
static int grub_lexer_resplit (const char *input, yyscan_t yyscanner);
2010-01-22 13:37:27 +00:00
static void grub_lexer_yyfree (void *, yyscan_t yyscanner);
static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner);
static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner);
2010-01-22 18:44:00 +00:00
static void copy_string (struct grub_parser_param *, const char *,
unsigned hint);
2010-01-22 13:37:27 +00:00
%}
%top{
2010-03-28 20:20:32 +00:00
#include <sys/types.h>
typedef size_t yy_size_t;
#define YY_TYPEDEF_YY_SIZE_T 1
2010-01-22 13:37:27 +00:00
/*
* Some flex hacks for -nostdinc; XXX We need to fix these when libc
* support becomes availble in GRUB.
*/
2010-03-28 20:20:32 +00:00
#ifndef GRUB_UTIL
2010-01-22 13:37:27 +00:00
#define stdin 0
#define stdout 0
#define fprintf(...) 0
#define exit(...)
2010-03-28 20:20:32 +00:00
#endif
2010-01-22 13:37:27 +00:00
}
%option ecs
%option meta-ecs
%option warn
%option array
%option stack
%option reentrant
%option bison-bridge
%option never-interactive
%option noyyfree noyyalloc noyyrealloc
2010-06-12 05:36:02 +00:00
%option nounistd nostdinit nodefault noyylineno
2010-01-22 13:37:27 +00:00
/* Reduce lexer size, by not defining these. */
2010-06-12 05:42:38 +00:00
%option noyy_top_state
2010-01-22 13:37:27 +00:00
%option noinput nounput
%option noyyget_in noyyset_in
%option noyyget_out noyyset_out
%option noyyget_debug noyyset_debug
%option noyyget_lineno noyyset_lineno
%option extra-type="struct grub_parser_param*"
BLANK [ \t]
2010-04-30 08:20:41 +00:00
COMMENT #.*$
2010-01-22 13:37:27 +00:00
2010-04-30 08:20:41 +00:00
CHAR [^{}|&$;<> \t\n\'\"\\]
2010-01-22 13:37:27 +00:00
DIGITS [[:digit:]]+
NAME [[:alpha:]_][[:alnum:][:digit:]_]*
ESC \\.
2010-06-12 05:36:02 +00:00
SQCHR [^\']
2010-06-12 05:45:53 +00:00
DQCHR {ESC}|[^\\\"]
2010-06-12 05:36:02 +00:00
DQSTR \"{DQCHR}*\"
SQSTR \'{SQCHR}*\'
2010-01-22 13:37:27 +00:00
VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\}
WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+
2010-06-12 05:36:02 +00:00
MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*))
2010-06-11 08:29:07 +00:00
2010-01-22 13:37:27 +00:00
%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_NOT; }
"{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
"}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
"[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
"]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
"time" { RECORD; return GRUB_PARSER_TOKEN_TIME; }
"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; }
"menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; }
{NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
{WORD} {
RECORD;
2010-06-11 08:29:07 +00:00
yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
2010-06-12 05:36:02 +00:00
if (grub_lexer_resplit (yytext, yyscanner))
2010-06-11 08:29:07 +00:00
{
yypop_buffer_state (yyscanner);
return GRUB_PARSER_TOKEN_WORD;
}
2010-06-12 05:42:38 +00:00
yyextra->lexerstate->resplit = 1;
2010-06-11 08:29:07 +00:00
}
2010-06-12 05:36:02 +00:00
{MULTILINE} {
if (grub_lexer_unput (yytext, yyscanner))
return GRUB_PARSER_TOKEN_BAD;
}
. {
grub_script_yyerror (yyextra, yytext);
return GRUB_PARSER_TOKEN_BAD;
2010-06-11 08:29:07 +00:00
}
2010-01-22 13:37:27 +00:00
/* Split word into multiple args */
<SPLIT>{
2010-01-22 18:44:00 +00:00
\\. { COPY (yytext + 1, yyleng - 1); }
2010-01-22 13:37:27 +00:00
\" {
2010-01-22 18:44:00 +00:00
yy_push_state (DQUOTE, yyscanner);
2010-01-22 13:37:27 +00:00
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
\' {
2010-01-22 18:44:00 +00:00
yy_push_state (SQUOTE, yyscanner);
2010-01-22 13:37:27 +00:00
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
\$ {
yy_push_state (VAR, yyscanner);
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
2010-01-22 18:44:00 +00:00
}
\\ |
[^\"\'\$\\]+ { COPY (yytext, yyleng); }
2010-01-22 13:37:27 +00:00
<<EOF>> {
2010-01-22 18:44:00 +00:00
yy_pop_state (yyscanner);
yypop_buffer_state (yyscanner);
2010-06-12 05:36:02 +00:00
yyextra->lexerstate->resplit = 0;
2010-01-22 18:44:00 +00:00
yyextra->lexerstate->merge_end = 1;
2010-01-22 13:37:27 +00:00
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
}
<VAR>{
\? |
{DIGITS} |
{NAME} {
2010-01-22 18:44:00 +00:00
COPY (yytext, yyleng);
yy_pop_state (yyscanner);
if (YY_START == SPLIT)
ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
else
ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
}
2010-01-22 13:37:27 +00:00
\{\?\} |
\{{DIGITS}\} |
\{{NAME}\} {
yytext[yyleng - 1] = '\0';
2010-01-22 18:44:00 +00:00
COPY (yytext + 1, yyleng - 2);
2010-01-22 13:37:27 +00:00
yy_pop_state (yyscanner);
2010-01-22 18:44:00 +00:00
if (YY_START == SPLIT)
ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
else
ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
2010-01-22 13:37:27 +00:00
}
.|\n { return GRUB_PARSER_TOKEN_BAD; }
}
<SQUOTE>{
\' {
yy_pop_state (yyscanner);
2010-01-22 18:44:00 +00:00
ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
2010-01-22 13:37:27 +00:00
}
2010-01-22 18:44:00 +00:00
[^\']+ { COPY (yytext, yyleng); }
2010-01-22 13:37:27 +00:00
}
<DQUOTE>{
\\\$ { COPY ("$", 1); }
\\\\ { COPY ("\\", 1); }
\\\" { COPY ("\"", 1); }
\\\n { /* ignore */ }
[^\"\$\\\n]+ { COPY (yytext, yyleng); }
2010-01-22 13:37:27 +00:00
\" {
yy_pop_state (yyscanner);
2010-01-22 18:44:00 +00:00
ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
2010-01-22 13:37:27 +00:00
}
\$ {
yy_push_state (VAR, yyscanner);
2010-01-22 18:44:00 +00:00
ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
}
(.|\n) { COPY (yytext, yyleng); }
2010-01-22 13:37:27 +00:00
}
<<EOF>> {
2010-01-22 18:44:00 +00:00
yypop_buffer_state (yyscanner);
2010-06-12 05:36:02 +00:00
yyextra->lexerstate->eof = 1;
return GRUB_PARSER_TOKEN_EOF;
2010-01-22 13:37:27 +00:00
}
%%
2010-06-11 08:29:07 +00:00
int
yywrap (yyscan_t yyscanner)
{
2010-06-12 05:36:02 +00:00
if (yyget_extra (yyscanner)->lexerstate->resplit)
return 1;
2010-06-11 08:29:07 +00:00
2010-06-12 05:36:02 +00:00
return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
2010-06-11 08:29:07 +00:00
}
2010-01-22 13:37:27 +00:00
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);
}
2010-01-22 18:44:00 +00:00
static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
{
int size;
char *ptr;
unsigned len;
2010-01-22 18:44:00 +00:00
len = hint ? hint : grub_strlen (str);
if (parser->lexerstate->used + len >= parser->lexerstate->size)
{
2010-06-11 08:29:07 +00:00
size = grub_max (len, parser->lexerstate->size) * 2;
2010-01-22 18:44:00 +00:00
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;
}
2010-06-11 08:29:07 +00:00
static int
2010-06-12 05:36:02 +00:00
grub_lexer_resplit (const char *text, yyscan_t yyscanner)
2010-06-11 08:29:07 +00:00
{
/* 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;
}
2010-06-12 05:36:02 +00:00
static int
grub_lexer_unput (const char *text, yyscan_t yyscanner)
{
struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
if (lexerstate->prefix)
2010-06-12 05:42:38 +00:00
grub_free (lexerstate->prefix);
2010-06-12 05:36:02 +00:00
lexerstate->prefix = grub_strdup (text);
if (! lexerstate->prefix)
{
grub_script_yyerror (yyget_extra (yyscanner), "out of memory");
return 1;
}
return 0;
}