%{ /* 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 . */ #include #include #include #include #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) #define COPY(str, hint) \ do { \ copy_string (yyextra, str, hint); \ } while (0) #define RECORD \ do { \ grub_script_lexer_record (yyextra, yytext); \ } while (0) #define ARG(t) \ do { \ 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 */ 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); static void copy_string (struct grub_parser_param *, const char *, unsigned hint); %} %top{ #include typedef size_t yy_size_t; #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 } %option ecs %option meta-ecs %option warn %option array %option stack %option reentrant %option bison-bridge %option never-interactive %option noyyfree noyyalloc noyyrealloc %option nounistd nostdinit nodefault noyylineno noyywrap /* 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] COMMENT #.*$ CHAR [^{}|&$;<> \t\n\'\"\\] DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:][:digit:]_]* ESC \\. SPECIAL \?|\#|\*|\@ VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} DQSTR \"([^\\\"]|{ESC})*\" SQSTR \'[^\']*\' WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ %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; } {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } {WORD} { RECORD; /* resplit yytext */ grub_dprintf ("lexer", "word: [%s]\n", yytext); yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); if (yy_scan_string (yytext, yyscanner)) { yyextra->lexerstate->merge_start = 1; yy_push_state (SPLIT, yyscanner); } else { grub_script_yyerror (yyextra, 0); yypop_buffer_state (yyscanner); return GRUB_PARSER_TOKEN_WORD; } } .|\n { grub_script_yyerror (yyextra, "unrecognized token"); return GRUB_PARSER_TOKEN_BAD; } /* Split word into multiple args */ { \\. { COPY (yytext + 1, yyleng - 1); } \" { 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); } <> { yy_pop_state (yyscanner); yypop_buffer_state (yyscanner); yyextra->lexerstate->merge_end = 1; ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); } } { {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; } } { \' { yy_pop_state (yyscanner); ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR); } [^\']+ { COPY (yytext, yyleng); } } { \\\$ { 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); } } <> { yypop_buffer_state (yyscanner); if (! grub_script_lexer_yywrap (yyextra)) { yyextra->lexerstate->eof = 1; return GRUB_PARSER_TOKEN_EOF; } } %% 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); } #define MAX(a,b) ((a) < (b) ? (b) : (a)) static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint) { int size; char *ptr; unsigned len; len = hint ? hint : grub_strlen (str); if (parser->lexerstate->used + len >= parser->lexerstate->size) { size = MAX (len, 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; }