yylex.l 11.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
%{
/* 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>
25
#include <grub/i18n.h>
26 27
#include "grub_script.tab.h"

28 29
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
30
#pragma GCC diagnostic ignored "-Wmissing-declarations"
31 32
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wsign-compare"
33

34 35 36
#define yyalloc(size, scanner)   (grub_malloc((size)))
#define yyfree(ptr, scanner)   (grub_free((ptr)))
#define yyrealloc(ptr, size, scanner) (grub_realloc((ptr), (size)))
37 38 39 40 41 42 43

/* 
 * As we don't have access to yyscanner, we cannot do much except to
 * print the fatal error.
 */
#define YY_FATAL_ERROR(msg)                     \
  do {                                          \
44
    grub_printf (_("fatal error: %s\n"), _(msg));     \
45 46
  } while (0)

47 48 49
#define COPY(str, hint)                         \
  do {                                          \
    copy_string (yyextra, str, hint);           \
50 51
  } while (0)

52 53 54 55

#define RECORD                                  \
  do {                                          \
    grub_script_lexer_record (yyextra, yytext); \
56 57
  } while (0)

58 59
#define ARG(t)                        \
  do {                                \
60 61 62 63 64 65 66 67
    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 */
BVK Chaitanya's avatar
BVK Chaitanya committed
68 69 70
static int grub_lexer_unput (const char *input, yyscan_t yyscanner);
static int grub_lexer_resplit (const char *input, yyscan_t yyscanner);

71 72
static void  copy_string (struct grub_parser_param *, const char *,
                          unsigned hint);
73 74 75 76 77

%}

%top{

78 79
#include <config.h>

80 81 82 83 84
#include <sys/types.h>

typedef size_t yy_size_t;
#define YY_TYPEDEF_YY_SIZE_T 1

85 86 87 88 89
/* 
 * Some flex hacks for -nostdinc; XXX We need to fix these when libc
 * support becomes availble in GRUB.
 */

90
#ifndef GRUB_UTIL
91 92 93 94
#define stdin  0
#define stdout 0

#define fprintf(...) 0
95
#define exit(...) grub_fatal("fatal error in lexer")
96
#endif
97 98 99 100 101 102 103 104 105 106 107 108 109 110

}

%option ecs
%option meta-ecs

%option warn
%option array
%option stack
%option reentrant
%option bison-bridge
%option never-interactive

%option noyyfree noyyalloc noyyrealloc
BVK Chaitanya's avatar
BVK Chaitanya committed
111
%option nounistd nostdinit nodefault noyylineno
112 113 114 115 116 117 118 119 120 121 122 123

/* Reduce lexer size, by not defining these.  */
%option noyy_top_state
%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]
124
COMMENT         #.*$
125

126
CHAR            [^{}|&$;<> \t\n\'\"\\]
127
DIGITS          [[:digit:]]+
128
NAME            [[:alpha:]_][[:alnum:]_]*
129

130
ESC             \\(.|\n)
BVK Chaitanya's avatar
BVK Chaitanya committed
131
SQCHR           [^\']
132
DQCHR           {ESC}|[^\\\"]
BVK Chaitanya's avatar
BVK Chaitanya committed
133
DQSTR           \"{DQCHR}*\"
134
I18NSTR         \$\"{DQCHR}*\"
BVK Chaitanya's avatar
BVK Chaitanya committed
135
SQSTR           \'{SQCHR}*\'
136
SPECIAL         \?|\#|\*|\@
137
VARIABLE        ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
138
WORD            ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE}|{I18NSTR})+
139

140 141
MULTILINE       {WORD}?((\"{DQCHR}*)|(\$\"{DQCHR}*)|(\'{SQCHR}*))
POS_MULTILINE   {WORD}?\\\n
142

143 144
%x              SPLIT
%x              DQUOTE
145
%x              I18NQUOTE
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
%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;       }
169 170
"[["            { RECORD; return GRUB_PARSER_TOKEN_LSQBR2;    }
"]]"            { RECORD; return GRUB_PARSER_TOKEN_RSQBR2;    }
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
"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;  }

187 188 189 190 191
{MULTILINE}     {
                  if (grub_lexer_unput (yytext, yyscanner))
		    return GRUB_PARSER_TOKEN_BAD;
		}

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
{POS_MULTILINE} {
                  if (yyg->yy_c_buf_p + 1 == &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
		    {
		      if (grub_lexer_unput (yytext, yyscanner))
			return GRUB_PARSER_TOKEN_BAD;
		    }
		  else
		    {
		      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;
		    }
		}


212 213 214
{NAME}          { RECORD; return GRUB_PARSER_TOKEN_NAME; }
{WORD}          {
                  RECORD;
215
		  yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
BVK Chaitanya's avatar
BVK Chaitanya committed
216
		  if (grub_lexer_resplit (yytext, yyscanner))
217 218 219 220
		    {
		      yypop_buffer_state (yyscanner);
		      return GRUB_PARSER_TOKEN_WORD;
		    }
BVK Chaitanya's avatar
BVK Chaitanya committed
221
		  yyextra->lexerstate->resplit = 1;
222
                }
BVK Chaitanya's avatar
BVK Chaitanya committed
223 224 225
.               {
                  grub_script_yyerror (yyextra, yytext);
		  return GRUB_PARSER_TOKEN_BAD;
226 227 228 229 230
                }

 /* Split word into multiple args */

<SPLIT>{
231
  \\.           { COPY (yytext, yyleng); }
232
  \\\n          { /* ignore */ }
233
  \"            {
234
                  yy_push_state (DQUOTE, yyscanner);
235 236 237
                  ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
                }
  \'            {
238
                  yy_push_state (SQUOTE, yyscanner);
239 240
                  ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
                }
241 242 243 244
  "\$\""        {
                  yy_push_state (I18NQUOTE, yyscanner);
                  ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
                }
245 246 247
  \$            {
                  yy_push_state (VAR, yyscanner);
                  ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
248 249
                }
  \\            |
250
  [^\"\'\$\\]+  { COPY (yytext, yyleng); }
251
  <<EOF>>       {
252 253
                  yy_pop_state (yyscanner);
                  yypop_buffer_state (yyscanner);
BVK Chaitanya's avatar
BVK Chaitanya committed
254
		  yyextra->lexerstate->resplit = 0;
255
                  yyextra->lexerstate->merge_end = 1;
256 257 258 259 260
                  ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
                }
}

<VAR>{
261
  {SPECIAL}     |
262 263
  {DIGITS}      |
  {NAME}        {
264 265 266 267 268 269 270
                  COPY (yytext, yyleng);
                  yy_pop_state (yyscanner);
                  if (YY_START == SPLIT)
                    ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
                  else
                    ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
                }
271
  \{{SPECIAL}\} |
272 273 274
  \{{DIGITS}\}  |
  \{{NAME}\}    {
                  yytext[yyleng - 1] = '\0';
275
                  COPY (yytext + 1, yyleng - 2);
276
                  yy_pop_state (yyscanner);
277 278 279 280
                  if (YY_START == SPLIT)
                    ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
                  else
                    ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
281 282 283 284 285 286 287
                }
  .|\n          { return GRUB_PARSER_TOKEN_BAD; }
}

<SQUOTE>{
  \'            {
                  yy_pop_state (yyscanner);
288
                  ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
289
                }
290
  [^\']+        { COPY (yytext, yyleng); }
291 292 293
}

<DQUOTE>{
294 295 296 297 298
  \\\$          { COPY ("$", 1); }
  \\\\          { COPY ("\\", 1); }
  \\\"          { COPY ("\"", 1); }
  \\\n          { /* ignore */ }
  [^\"\$\\\n]+  { COPY (yytext, yyleng); }
299 300
  \"            {
                  yy_pop_state (yyscanner);
301
                  ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
302 303 304
                }
  \$            {
                  yy_push_state (VAR, yyscanner);
305 306 307
                  ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
                }
  (.|\n)        { COPY (yytext, yyleng); }
308 309
}

310
<I18NQUOTE>{
311
  \\\\          { COPY ("\\\\", 2); }
312 313 314 315 316 317 318
  \\\"          { COPY ("\"", 1); }
  \\\n          { /* ignore */ }
  [^\"\\\n]+    { COPY (yytext, yyleng); }
  \"            {
                  yy_pop_state (yyscanner);
                  ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
                }
319
  \\            { COPY ("\\", 1); }
320 321 322
  (.|\n)        { COPY (yytext, yyleng); }
}

323
<<EOF>>         {
324
                  yypop_buffer_state (yyscanner);
BVK Chaitanya's avatar
BVK Chaitanya committed
325 326
		  yyextra->lexerstate->eof = 1;
		  return GRUB_PARSER_TOKEN_EOF;
327 328 329
                }
%%

330 331 332
int
yywrap (yyscan_t yyscanner)
{
BVK Chaitanya's avatar
BVK Chaitanya committed
333 334
  if (yyget_extra (yyscanner)->lexerstate->resplit)
    return 1;
335

BVK Chaitanya's avatar
BVK Chaitanya committed
336
  return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
337 338
}

339 340
static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
{
341
  grub_size_t size;
342
  char *ptr;
343
  unsigned len;
344 345 346 347

  len = hint ? hint : grub_strlen (str);
  if (parser->lexerstate->used + len >= parser->lexerstate->size)
    {
348 349 350
      size = len * 2;
      if (size < parser->lexerstate->size * 2)
        size = parser->lexerstate->size * 2;
351 352 353 354 355 356 357 358 359 360 361 362 363
      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;
}
364 365

static int
BVK Chaitanya's avatar
BVK Chaitanya committed
366
grub_lexer_resplit (const char *text, yyscan_t yyscanner)
367 368 369 370 371 372 373 374 375 376 377
{
  /* 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;
}
BVK Chaitanya's avatar
BVK Chaitanya committed
378 379 380 381 382 383

static int
grub_lexer_unput (const char *text, yyscan_t yyscanner)
{
  struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;

384
  grub_free (lexerstate->prefix);
BVK Chaitanya's avatar
BVK Chaitanya committed
385 386 387 388

  lexerstate->prefix = grub_strdup (text);
  if (! lexerstate->prefix)
    {
389
      grub_script_yyerror (yyget_extra (yyscanner), N_("out of memory"));
BVK Chaitanya's avatar
BVK Chaitanya committed
390 391 392 393
      return 1;
    }
  return 0;
}