yylex.l 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. %{
  2. /* yylex.l The scripting lexer. */
  3. /*
  4. * GRUB -- GRand Unified Bootloader
  5. * Copyright (C) 2009,2010 Free Software Foundation, Inc.
  6. *
  7. * GRUB is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * GRUB is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <grub/parser.h>
  21. #include <grub/misc.h>
  22. #include <grub/mm.h>
  23. #include <grub/script_sh.h>
  24. #include "grub_script.tab.h"
  25. #define yyfree grub_lexer_yyfree
  26. #define yyalloc grub_lexer_yyalloc
  27. #define yyrealloc grub_lexer_yyrealloc
  28. /*
  29. * As we don't have access to yyscanner, we cannot do much except to
  30. * print the fatal error.
  31. */
  32. #define YY_FATAL_ERROR(msg) \
  33. do { \
  34. grub_printf ("fatal error: %s\n", msg); \
  35. } while (0)
  36. #define COPY(str, hint) \
  37. do { \
  38. copy_string (yyextra, str, hint); \
  39. } while (0)
  40. #define RECORD \
  41. do { \
  42. grub_script_lexer_record (yyextra, yytext); \
  43. } while (0)
  44. #define ARG(t) \
  45. do { \
  46. yyextra->lexerstate->type = t; \
  47. return GRUB_PARSER_TOKEN_WORD; \
  48. } while (0)
  49. /* We don't need YY_INPUT, as we rely on yy_scan_strings */
  50. #define YY_INPUT(buf,res,max) do { res = 0; } while (0)
  51. /* forward declarations */
  52. static void grub_lexer_yyfree (void *, yyscan_t yyscanner);
  53. static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner);
  54. static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner);
  55. static void copy_string (struct grub_parser_param *, const char *,
  56. unsigned hint);
  57. %}
  58. %top{
  59. #include <sys/types.h>
  60. typedef size_t yy_size_t;
  61. #define YY_TYPEDEF_YY_SIZE_T 1
  62. /*
  63. * Some flex hacks for -nostdinc; XXX We need to fix these when libc
  64. * support becomes availble in GRUB.
  65. */
  66. #ifndef GRUB_UTIL
  67. #define stdin 0
  68. #define stdout 0
  69. #define fprintf(...) 0
  70. #define exit(...)
  71. #endif
  72. }
  73. %option ecs
  74. %option meta-ecs
  75. %option warn
  76. %option array
  77. %option stack
  78. %option reentrant
  79. %option bison-bridge
  80. %option never-interactive
  81. %option noyyfree noyyalloc noyyrealloc
  82. %option nounistd nostdinit nodefault noyylineno noyywrap
  83. /* Reduce lexer size, by not defining these. */
  84. %option noyy_top_state
  85. %option noinput nounput
  86. %option noyyget_in noyyset_in
  87. %option noyyget_out noyyset_out
  88. %option noyyget_debug noyyset_debug
  89. %option noyyget_lineno noyyset_lineno
  90. %option extra-type="struct grub_parser_param*"
  91. BLANK [ \t]
  92. COMMENT #.*$
  93. CHAR [^{}|&$;<> \t\n\'\"\\]
  94. DIGITS [[:digit:]]+
  95. NAME [[:alpha:]_][[:alnum:][:digit:]_]*
  96. ESC \\.
  97. VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\}
  98. DQSTR \"([^\\\"]|{ESC})*\"
  99. SQSTR \'[^\']*\'
  100. WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+
  101. %x SPLIT
  102. %x DQUOTE
  103. %x SQUOTE
  104. %x VAR
  105. %%
  106. /* White spaces */
  107. {BLANK}+ { RECORD; }
  108. {COMMENT} { RECORD; }
  109. /* Special symbols */
  110. "\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
  111. "||" { RECORD; return GRUB_PARSER_TOKEN_OR; }
  112. "&&" { RECORD; return GRUB_PARSER_TOKEN_AND; }
  113. ";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; }
  114. "|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; }
  115. "&" { RECORD; return GRUB_PARSER_TOKEN_AMP; }
  116. ";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; }
  117. "<" { RECORD; return GRUB_PARSER_TOKEN_LT; }
  118. ">" { RECORD; return GRUB_PARSER_TOKEN_GT; }
  119. /* Reserved words */
  120. "!" { RECORD; return GRUB_PARSER_TOKEN_NOT; }
  121. "{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
  122. "}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
  123. "[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
  124. "]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
  125. "case" { RECORD; return GRUB_PARSER_TOKEN_CASE; }
  126. "do" { RECORD; return GRUB_PARSER_TOKEN_DO; }
  127. "done" { RECORD; return GRUB_PARSER_TOKEN_DONE; }
  128. "elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; }
  129. "else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; }
  130. "esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; }
  131. "fi" { RECORD; return GRUB_PARSER_TOKEN_FI; }
  132. "for" { RECORD; return GRUB_PARSER_TOKEN_FOR; }
  133. "if" { RECORD; return GRUB_PARSER_TOKEN_IF; }
  134. "in" { RECORD; return GRUB_PARSER_TOKEN_IN; }
  135. "select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; }
  136. "then" { RECORD; return GRUB_PARSER_TOKEN_THEN; }
  137. "until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; }
  138. "while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; }
  139. "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; }
  140. "menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; }
  141. {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
  142. {WORD} {
  143. RECORD;
  144. /* resplit yytext */
  145. grub_dprintf ("lexer", "word: [%s]\n", yytext);
  146. yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
  147. if (yy_scan_string (yytext, yyscanner))
  148. {
  149. yyextra->lexerstate->merge_start = 1;
  150. yy_push_state (SPLIT, yyscanner);
  151. }
  152. else
  153. {
  154. grub_script_yyerror (yyextra, 0);
  155. yypop_buffer_state (yyscanner);
  156. return GRUB_PARSER_TOKEN_WORD;
  157. }
  158. }
  159. .|\n {
  160. grub_script_yyerror (yyextra, "unrecognized token");
  161. return GRUB_PARSER_TOKEN_BAD;
  162. }
  163. /* Split word into multiple args */
  164. <SPLIT>{
  165. \\. { COPY (yytext + 1, yyleng - 1); }
  166. \" {
  167. yy_push_state (DQUOTE, yyscanner);
  168. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  169. }
  170. \' {
  171. yy_push_state (SQUOTE, yyscanner);
  172. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  173. }
  174. \$ {
  175. yy_push_state (VAR, yyscanner);
  176. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  177. }
  178. \\ |
  179. [^\"\'\$\\]+ { COPY (yytext, yyleng); }
  180. <<EOF>> {
  181. yy_pop_state (yyscanner);
  182. yypop_buffer_state (yyscanner);
  183. yyextra->lexerstate->merge_end = 1;
  184. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  185. }
  186. }
  187. <VAR>{
  188. \? |
  189. {DIGITS} |
  190. {NAME} {
  191. COPY (yytext, yyleng);
  192. yy_pop_state (yyscanner);
  193. if (YY_START == SPLIT)
  194. ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
  195. else
  196. ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
  197. }
  198. \{\?\} |
  199. \{{DIGITS}\} |
  200. \{{NAME}\} {
  201. yytext[yyleng - 1] = '\0';
  202. COPY (yytext + 1, yyleng - 2);
  203. yy_pop_state (yyscanner);
  204. if (YY_START == SPLIT)
  205. ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
  206. else
  207. ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
  208. }
  209. .|\n { return GRUB_PARSER_TOKEN_BAD; }
  210. }
  211. <SQUOTE>{
  212. \' {
  213. yy_pop_state (yyscanner);
  214. ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
  215. }
  216. [^\']+ { COPY (yytext, yyleng); }
  217. }
  218. <DQUOTE>{
  219. \\\$ { COPY ("$", 1); }
  220. \\\\ { COPY ("\\", 1); }
  221. \\\" { COPY ("\"", 1); }
  222. \\\n { /* ignore */ }
  223. [^\"\$\\\n]+ { COPY (yytext, yyleng); }
  224. \" {
  225. yy_pop_state (yyscanner);
  226. ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
  227. }
  228. \$ {
  229. yy_push_state (VAR, yyscanner);
  230. ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
  231. }
  232. (.|\n) { COPY (yytext, yyleng); }
  233. }
  234. <<EOF>> {
  235. yypop_buffer_state (yyscanner);
  236. if (! grub_script_lexer_yywrap (yyextra))
  237. {
  238. yyextra->lexerstate->eof = 1;
  239. return GRUB_PARSER_TOKEN_EOF;
  240. }
  241. }
  242. %%
  243. static void
  244. grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused)))
  245. {
  246. grub_free(ptr);
  247. }
  248. static void*
  249. grub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused)))
  250. {
  251. return grub_malloc (size);
  252. }
  253. static void*
  254. grub_lexer_yyrealloc (void *ptr, yy_size_t size,
  255. yyscan_t yyscanner __attribute__ ((unused)))
  256. {
  257. return grub_realloc (ptr, size);
  258. }
  259. #define MAX(a,b) ((a) < (b) ? (b) : (a))
  260. static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
  261. {
  262. int size;
  263. char *ptr;
  264. unsigned len;
  265. len = hint ? hint : grub_strlen (str);
  266. if (parser->lexerstate->used + len >= parser->lexerstate->size)
  267. {
  268. size = MAX (len, parser->lexerstate->size) * 2;
  269. ptr = grub_realloc (parser->lexerstate->text, size);
  270. if (!ptr)
  271. {
  272. grub_script_yyerror (parser, 0);
  273. return;
  274. }
  275. parser->lexerstate->text = ptr;
  276. parser->lexerstate->size = size;
  277. }
  278. grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
  279. parser->lexerstate->used += len;
  280. }