2N/A%{
2N/A/* yylex.l The scripting lexer. */
2N/A/*
2N/A * GRUB -- GRand Unified Bootloader
2N/A * Copyright (C) 2009,2010 Free Software Foundation, Inc.
2N/A *
2N/A * GRUB is free software: you can redistribute it and/or modify
2N/A * it under the terms of the GNU General Public License as published by
2N/A * the Free Software Foundation, either version 3 of the License, or
2N/A * (at your option) any later version.
2N/A *
2N/A * GRUB is distributed in the hope that it will be useful,
2N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A * GNU General Public License for more details.
2N/A *
2N/A * You should have received a copy of the GNU General Public License
2N/A * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
2N/A */
2N/A
2N/A#include <grub/parser.h>
2N/A#include <grub/misc.h>
2N/A#include <grub/mm.h>
2N/A#include <grub/script_sh.h>
2N/A#include "grub_script.tab.h"
2N/A
2N/A#pragma GCC diagnostic ignored "-Wunused-parameter"
2N/A#pragma GCC diagnostic ignored "-Wmissing-prototypes"
2N/A
2N/A#define yyfree grub_lexer_yyfree
2N/A#define yyalloc grub_lexer_yyalloc
2N/A#define yyrealloc grub_lexer_yyrealloc
2N/A
2N/A/*
2N/A * As we don't have access to yyscanner, we cannot do much except to
2N/A * print the fatal error.
2N/A */
2N/A#define YY_FATAL_ERROR(msg) \
2N/A do { \
2N/A grub_printf ("fatal error: %s\n", msg); \
2N/A } while (0)
2N/A
2N/A#define COPY(str, hint) \
2N/A do { \
2N/A copy_string (yyextra, str, hint); \
2N/A } while (0)
2N/A
2N/A
2N/A#define RECORD \
2N/A do { \
2N/A grub_script_lexer_record (yyextra, yytext); \
2N/A } while (0)
2N/A
2N/A#define ARG(t) \
2N/A do { \
2N/A yyextra->lexerstate->type = t; \
2N/A return GRUB_PARSER_TOKEN_WORD; \
2N/A } while (0)
2N/A
2N/A/* We don't need YY_INPUT, as we rely on yy_scan_strings */
2N/A#define YY_INPUT(buf,res,max) do { res = 0; } while (0)
2N/A
2N/A/* forward declarations */
2N/Astatic int grub_lexer_unput (const char *input, yyscan_t yyscanner);
2N/Astatic int grub_lexer_resplit (const char *input, yyscan_t yyscanner);
2N/A
2N/Astatic void grub_lexer_yyfree (void *, yyscan_t yyscanner);
2N/Astatic void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner);
2N/Astatic void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner);
2N/Astatic void copy_string (struct grub_parser_param *, const char *,
2N/A unsigned hint);
2N/A
2N/A%}
2N/A
2N/A%top{
2N/A
2N/A#include <config.h>
2N/A
2N/A#include <sys/types.h>
2N/A
2N/Atypedef size_t yy_size_t;
2N/A#define YY_TYPEDEF_YY_SIZE_T 1
2N/A
2N/A/*
2N/A * Some flex hacks for -nostdinc; XXX We need to fix these when libc
2N/A * support becomes availble in GRUB.
2N/A */
2N/A
2N/A#ifndef GRUB_UTIL
2N/A#define stdin 0
2N/A#define stdout 0
2N/A
2N/A#define fprintf(...) 0
2N/A#define exit(...)
2N/A#endif
2N/A
2N/A}
2N/A
2N/A%option ecs
2N/A%option meta-ecs
2N/A
2N/A%option warn
2N/A%option array
2N/A%option stack
2N/A%option reentrant
2N/A%option bison-bridge
2N/A%option never-interactive
2N/A
2N/A%option noyyfree noyyalloc noyyrealloc
2N/A%option nounistd nostdinit nodefault noyylineno
2N/A
2N/A/* Reduce lexer size, by not defining these. */
2N/A%option noyy_top_state
2N/A%option noinput nounput
2N/A%option noyyget_in noyyset_in
2N/A%option noyyget_out noyyset_out
2N/A%option noyyget_debug noyyset_debug
2N/A%option noyyget_lineno noyyset_lineno
2N/A
2N/A%option extra-type="struct grub_parser_param*"
2N/A
2N/ABLANK [ \t]
2N/ACOMMENT #.*$
2N/A
2N/ACHAR [^{}|&$;<> \t\n\'\"\\]
2N/ADIGITS [[:digit:]]+
2N/ANAME [[:alpha:]_][[:alnum:]_]*
2N/A
2N/AESC \\(.|\n)
2N/ASQCHR [^\']
2N/ADQCHR {ESC}|[^\\\"]
2N/ADQSTR \"{DQCHR}*\"
2N/ASQSTR \'{SQCHR}*\'
2N/ASPECIAL \?|\#|\*|\@
2N/AVARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
2N/AWORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+
2N/A
2N/AMULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n))
2N/A
2N/A%x SPLIT
2N/A%x DQUOTE
2N/A%x SQUOTE
2N/A%x VAR
2N/A
2N/A%%
2N/A
2N/A /* White spaces */
2N/A{BLANK}+ { RECORD; }
2N/A{COMMENT} { RECORD; }
2N/A
2N/A /* Special symbols */
2N/A"\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
2N/A"||" { RECORD; return GRUB_PARSER_TOKEN_OR; }
2N/A"&&" { RECORD; return GRUB_PARSER_TOKEN_AND; }
2N/A";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; }
2N/A"|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; }
2N/A"&" { RECORD; return GRUB_PARSER_TOKEN_AMP; }
2N/A";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; }
2N/A"<" { RECORD; return GRUB_PARSER_TOKEN_LT; }
2N/A">" { RECORD; return GRUB_PARSER_TOKEN_GT; }
2N/A
2N/A /* Reserved words */
2N/A"{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
2N/A"}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
2N/A"[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
2N/A"]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
2N/A"case" { RECORD; return GRUB_PARSER_TOKEN_CASE; }
2N/A"do" { RECORD; return GRUB_PARSER_TOKEN_DO; }
2N/A"done" { RECORD; return GRUB_PARSER_TOKEN_DONE; }
2N/A"elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; }
2N/A"else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; }
2N/A"esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; }
2N/A"fi" { RECORD; return GRUB_PARSER_TOKEN_FI; }
2N/A"for" { RECORD; return GRUB_PARSER_TOKEN_FOR; }
2N/A"if" { RECORD; return GRUB_PARSER_TOKEN_IF; }
2N/A"in" { RECORD; return GRUB_PARSER_TOKEN_IN; }
2N/A"select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; }
2N/A"then" { RECORD; return GRUB_PARSER_TOKEN_THEN; }
2N/A"until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; }
2N/A"while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; }
2N/A"function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; }
2N/A
2N/A{MULTILINE} {
2N/A if (grub_lexer_unput (yytext, yyscanner))
2N/A return GRUB_PARSER_TOKEN_BAD;
2N/A }
2N/A
2N/A{NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
2N/A{WORD} {
2N/A RECORD;
2N/A yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
2N/A if (grub_lexer_resplit (yytext, yyscanner))
2N/A {
2N/A yypop_buffer_state (yyscanner);
2N/A return GRUB_PARSER_TOKEN_WORD;
2N/A }
2N/A yyextra->lexerstate->resplit = 1;
2N/A }
2N/A. {
2N/A grub_script_yyerror (yyextra, yytext);
2N/A return GRUB_PARSER_TOKEN_BAD;
2N/A }
2N/A
2N/A /* Split word into multiple args */
2N/A
2N/A<SPLIT>{
2N/A \\. { COPY (yytext + 1, yyleng - 1); }
2N/A \\\n { /* ignore */ }
2N/A \" {
2N/A yy_push_state (DQUOTE, yyscanner);
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
2N/A }
2N/A \' {
2N/A yy_push_state (SQUOTE, yyscanner);
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
2N/A }
2N/A \$ {
2N/A yy_push_state (VAR, yyscanner);
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
2N/A }
2N/A \\ |
2N/A [^\"\'\$\\]+ { COPY (yytext, yyleng); }
2N/A <<EOF>> {
2N/A yy_pop_state (yyscanner);
2N/A yypop_buffer_state (yyscanner);
2N/A yyextra->lexerstate->resplit = 0;
2N/A yyextra->lexerstate->merge_end = 1;
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
2N/A }
2N/A}
2N/A
2N/A<VAR>{
2N/A {SPECIAL} |
2N/A {DIGITS} |
2N/A {NAME} {
2N/A COPY (yytext, yyleng);
2N/A yy_pop_state (yyscanner);
2N/A if (YY_START == SPLIT)
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
2N/A else
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
2N/A }
2N/A \{{SPECIAL}\} |
2N/A \{{DIGITS}\} |
2N/A \{{NAME}\} {
2N/A yytext[yyleng - 1] = '\0';
2N/A COPY (yytext + 1, yyleng - 2);
2N/A yy_pop_state (yyscanner);
2N/A if (YY_START == SPLIT)
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
2N/A else
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
2N/A }
2N/A .|\n { return GRUB_PARSER_TOKEN_BAD; }
2N/A}
2N/A
2N/A<SQUOTE>{
2N/A \' {
2N/A yy_pop_state (yyscanner);
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
2N/A }
2N/A [^\']+ { COPY (yytext, yyleng); }
2N/A}
2N/A
2N/A<DQUOTE>{
2N/A \\\$ { COPY ("$", 1); }
2N/A \\\\ { COPY ("\\", 1); }
2N/A \\\" { COPY ("\"", 1); }
2N/A \\\n { /* ignore */ }
2N/A [^\"\$\\\n]+ { COPY (yytext, yyleng); }
2N/A \" {
2N/A yy_pop_state (yyscanner);
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
2N/A }
2N/A \$ {
2N/A yy_push_state (VAR, yyscanner);
2N/A ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
2N/A }
2N/A (.|\n) { COPY (yytext, yyleng); }
2N/A}
2N/A
2N/A<<EOF>> {
2N/A yypop_buffer_state (yyscanner);
2N/A yyextra->lexerstate->eof = 1;
2N/A return GRUB_PARSER_TOKEN_EOF;
2N/A }
2N/A%%
2N/A
2N/Aint
2N/Ayywrap (yyscan_t yyscanner)
2N/A{
2N/A if (yyget_extra (yyscanner)->lexerstate->resplit)
2N/A return 1;
2N/A
2N/A return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
2N/A}
2N/A
2N/Astatic void
2N/Agrub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused)))
2N/A{
2N/A grub_free(ptr);
2N/A}
2N/A
2N/Astatic void*
2N/Agrub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused)))
2N/A{
2N/A return grub_malloc (size);
2N/A}
2N/A
2N/Astatic void*
2N/Agrub_lexer_yyrealloc (void *ptr, yy_size_t size,
2N/A yyscan_t yyscanner __attribute__ ((unused)))
2N/A{
2N/A return grub_realloc (ptr, size);
2N/A}
2N/A
2N/Astatic void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
2N/A{
2N/A grub_size_t size;
2N/A char *ptr;
2N/A unsigned len;
2N/A
2N/A len = hint ? hint : grub_strlen (str);
2N/A if (parser->lexerstate->used + len >= parser->lexerstate->size)
2N/A {
2N/A size = len * 2;
2N/A if (size < parser->lexerstate->size * 2)
2N/A size = parser->lexerstate->size * 2;
2N/A ptr = grub_realloc (parser->lexerstate->text, size);
2N/A if (!ptr)
2N/A {
2N/A grub_script_yyerror (parser, 0);
2N/A return;
2N/A }
2N/A
2N/A parser->lexerstate->text = ptr;
2N/A parser->lexerstate->size = size;
2N/A }
2N/A grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
2N/A parser->lexerstate->used += len;
2N/A}
2N/A
2N/Astatic int
2N/Agrub_lexer_resplit (const char *text, yyscan_t yyscanner)
2N/A{
2N/A /* resplit text */
2N/A if (yy_scan_string (text, yyscanner))
2N/A {
2N/A yyget_extra (yyscanner)->lexerstate->merge_start = 1;
2N/A yy_push_state (SPLIT, yyscanner);
2N/A return 0;
2N/A }
2N/A grub_script_yyerror (yyget_extra (yyscanner), 0);
2N/A return 1;
2N/A}
2N/A
2N/Astatic int
2N/Agrub_lexer_unput (const char *text, yyscan_t yyscanner)
2N/A{
2N/A struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
2N/A
2N/A grub_free (lexerstate->prefix);
2N/A
2N/A lexerstate->prefix = grub_strdup (text);
2N/A if (! lexerstate->prefix)
2N/A {
2N/A grub_script_yyerror (yyget_extra (yyscanner), "out of memory");
2N/A return 1;
2N/A }
2N/A return 0;
2N/A}