yylex.l 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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/i18n.h>
  25. #include "grub_script.tab.h"
  26. #pragma GCC diagnostic ignored "-Wunused-parameter"
  27. #pragma GCC diagnostic ignored "-Wmissing-prototypes"
  28. #pragma GCC diagnostic ignored "-Wmissing-declarations"
  29. #pragma GCC diagnostic ignored "-Wunused-function"
  30. #pragma GCC diagnostic ignored "-Wsign-compare"
  31. #define yyalloc(size, scanner) (grub_malloc((size)))
  32. #define yyfree(ptr, scanner) (grub_free((ptr)))
  33. #define yyrealloc(ptr, size, scanner) (grub_realloc((ptr), (size)))
  34. /*
  35. * As we don't have access to yyscanner, we cannot do much except to
  36. * print the fatal error and exit.
  37. */
  38. #define YY_FATAL_ERROR(msg) \
  39. do { \
  40. grub_fatal (_("fatal error: %s\n"), _(msg));\
  41. } while (0)
  42. #define COPY(str, hint) \
  43. do { \
  44. copy_string (yyextra, str, hint); \
  45. } while (0)
  46. #define RECORD \
  47. do { \
  48. grub_script_lexer_record (yyextra, yytext); \
  49. } while (0)
  50. #define ARG(t) \
  51. do { \
  52. yyextra->lexerstate->type = t; \
  53. return GRUB_PARSER_TOKEN_WORD; \
  54. } while (0)
  55. /* We don't need YY_INPUT, as we rely on yy_scan_strings */
  56. #define YY_INPUT(buf,res,max) do { res = 0; } while (0)
  57. /* forward declarations */
  58. static int grub_lexer_unput (const char *input, yyscan_t yyscanner);
  59. static int grub_lexer_resplit (const char *input, yyscan_t yyscanner);
  60. static void copy_string (struct grub_parser_param *, const char *,
  61. unsigned hint);
  62. %}
  63. %top{
  64. #include <config.h>
  65. #include <sys/types.h>
  66. typedef size_t yy_size_t;
  67. #define YY_TYPEDEF_YY_SIZE_T 1
  68. /*
  69. * Some flex hacks for -nostdinc; XXX We need to fix these when libc
  70. * support becomes availble in GRUB.
  71. */
  72. #ifndef GRUB_UTIL
  73. #define stdin 0
  74. #define stdout 0
  75. #define fprintf(...) (void)0
  76. #define exit(...) grub_fatal("fatal error in lexer")
  77. #endif
  78. }
  79. %option ecs
  80. %option meta-ecs
  81. %option warn
  82. %option array
  83. %option stack
  84. %option reentrant
  85. %option bison-bridge
  86. %option never-interactive
  87. %option noyyfree noyyalloc noyyrealloc
  88. %option nounistd nostdinit nodefault noyylineno
  89. /* Reduce lexer size, by not defining these. */
  90. %option noyy_top_state
  91. %option noinput nounput
  92. %option noyyget_in noyyset_in
  93. %option noyyget_out noyyset_out
  94. %option noyyget_debug noyyset_debug
  95. %option noyyget_lineno noyyset_lineno
  96. %option extra-type="struct grub_parser_param*"
  97. BLANK [ \t]
  98. COMMENT #.*$
  99. CHAR [^{}|&$;<> \t\n\'\"\\]
  100. DIGITS [[:digit:]]+
  101. NAME [[:alpha:]_][[:alnum:]_]*
  102. ESC \\(.|\n)
  103. SQCHR [^\']
  104. DQCHR {ESC}|[^\\\"]
  105. DQSTR \"{DQCHR}*\"
  106. I18NSTR \$\"{DQCHR}*\"
  107. SQSTR \'{SQCHR}*\'
  108. SPECIAL \?|\#|\*|\@
  109. VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
  110. WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE}|{I18NSTR})+
  111. MULTILINE {WORD}?((\"{DQCHR}*)|(\$\"{DQCHR}*)|(\'{SQCHR}*))
  112. POS_MULTILINE {WORD}?\\\n
  113. %x SPLIT
  114. %x DQUOTE
  115. %x I18NQUOTE
  116. %x SQUOTE
  117. %x VAR
  118. %%
  119. /* White spaces */
  120. {BLANK}+ { RECORD; }
  121. {COMMENT} { RECORD; }
  122. /* Special symbols */
  123. "\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
  124. "||" { RECORD; return GRUB_PARSER_TOKEN_OR; }
  125. "&&" { RECORD; return GRUB_PARSER_TOKEN_AND; }
  126. ";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; }
  127. "|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; }
  128. "&" { RECORD; return GRUB_PARSER_TOKEN_AMP; }
  129. ";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; }
  130. "<" { RECORD; return GRUB_PARSER_TOKEN_LT; }
  131. ">" { RECORD; return GRUB_PARSER_TOKEN_GT; }
  132. /* Reserved words */
  133. "{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
  134. "}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
  135. "[[" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
  136. "]]" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
  137. "case" { RECORD; return GRUB_PARSER_TOKEN_CASE; }
  138. "do" { RECORD; return GRUB_PARSER_TOKEN_DO; }
  139. "done" { RECORD; return GRUB_PARSER_TOKEN_DONE; }
  140. "elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; }
  141. "else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; }
  142. "esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; }
  143. "fi" { RECORD; return GRUB_PARSER_TOKEN_FI; }
  144. "for" { RECORD; return GRUB_PARSER_TOKEN_FOR; }
  145. "if" { RECORD; return GRUB_PARSER_TOKEN_IF; }
  146. "in" { RECORD; return GRUB_PARSER_TOKEN_IN; }
  147. "select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; }
  148. "then" { RECORD; return GRUB_PARSER_TOKEN_THEN; }
  149. "until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; }
  150. "while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; }
  151. "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; }
  152. {MULTILINE} {
  153. if (grub_lexer_unput (yytext, yyscanner))
  154. return GRUB_PARSER_TOKEN_BAD;
  155. }
  156. {POS_MULTILINE} {
  157. if (yyg->yy_c_buf_p + 1 == &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
  158. {
  159. if (grub_lexer_unput (yytext, yyscanner))
  160. return GRUB_PARSER_TOKEN_BAD;
  161. }
  162. else
  163. {
  164. RECORD;
  165. yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
  166. if (grub_lexer_resplit (yytext, yyscanner))
  167. {
  168. yypop_buffer_state (yyscanner);
  169. return GRUB_PARSER_TOKEN_WORD;
  170. }
  171. yyextra->lexerstate->resplit = 1;
  172. }
  173. }
  174. {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
  175. {WORD} {
  176. RECORD;
  177. yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
  178. if (grub_lexer_resplit (yytext, yyscanner))
  179. {
  180. yypop_buffer_state (yyscanner);
  181. return GRUB_PARSER_TOKEN_WORD;
  182. }
  183. yyextra->lexerstate->resplit = 1;
  184. }
  185. . {
  186. grub_script_yyerror (yyextra, yytext);
  187. return GRUB_PARSER_TOKEN_BAD;
  188. }
  189. /* Split word into multiple args */
  190. <SPLIT>{
  191. \\. { COPY (yytext, yyleng); }
  192. \\\n { /* ignore */ }
  193. \" {
  194. yy_push_state (DQUOTE, yyscanner);
  195. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  196. }
  197. \' {
  198. yy_push_state (SQUOTE, yyscanner);
  199. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  200. }
  201. "\$\"" {
  202. yy_push_state (I18NQUOTE, yyscanner);
  203. ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
  204. }
  205. \$ {
  206. yy_push_state (VAR, yyscanner);
  207. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  208. }
  209. \\ |
  210. [^\"\'\$\\]+ { COPY (yytext, yyleng); }
  211. <<EOF>> {
  212. yy_pop_state (yyscanner);
  213. yypop_buffer_state (yyscanner);
  214. yyextra->lexerstate->resplit = 0;
  215. yyextra->lexerstate->merge_end = 1;
  216. ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
  217. }
  218. }
  219. <VAR>{
  220. {SPECIAL} |
  221. {DIGITS} |
  222. {NAME} {
  223. COPY (yytext, yyleng);
  224. yy_pop_state (yyscanner);
  225. if (YY_START == SPLIT)
  226. ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
  227. else
  228. ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
  229. }
  230. \{{SPECIAL}\} |
  231. \{{DIGITS}\} |
  232. \{{NAME}\} {
  233. yytext[yyleng - 1] = '\0';
  234. COPY (yytext + 1, yyleng - 2);
  235. yy_pop_state (yyscanner);
  236. if (YY_START == SPLIT)
  237. ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
  238. else
  239. ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
  240. }
  241. .|\n { return GRUB_PARSER_TOKEN_BAD; }
  242. }
  243. <SQUOTE>{
  244. \' {
  245. yy_pop_state (yyscanner);
  246. ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
  247. }
  248. [^\']+ { COPY (yytext, yyleng); }
  249. }
  250. <DQUOTE>{
  251. \\\$ { COPY ("$", 1); }
  252. \\\\ { COPY ("\\", 1); }
  253. \\\" { COPY ("\"", 1); }
  254. \\\n { /* ignore */ }
  255. [^\"\$\\\n]+ { COPY (yytext, yyleng); }
  256. \" {
  257. yy_pop_state (yyscanner);
  258. ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
  259. }
  260. \$ {
  261. yy_push_state (VAR, yyscanner);
  262. ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
  263. }
  264. (.|\n) { COPY (yytext, yyleng); }
  265. }
  266. <I18NQUOTE>{
  267. \\\\ { COPY ("\\\\", 2); }
  268. \\\" { COPY ("\"", 1); }
  269. \\\n { /* ignore */ }
  270. [^\"\\\n]+ { COPY (yytext, yyleng); }
  271. \" {
  272. yy_pop_state (yyscanner);
  273. ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
  274. }
  275. \\ { COPY ("\\", 1); }
  276. (.|\n) { COPY (yytext, yyleng); }
  277. }
  278. <<EOF>> {
  279. yypop_buffer_state (yyscanner);
  280. yyextra->lexerstate->eof = 1;
  281. return GRUB_PARSER_TOKEN_EOF;
  282. }
  283. %%
  284. int
  285. yywrap (yyscan_t yyscanner)
  286. {
  287. if (yyget_extra (yyscanner)->lexerstate->resplit)
  288. return 1;
  289. return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
  290. }
  291. static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
  292. {
  293. grub_size_t size;
  294. char *ptr;
  295. unsigned len;
  296. len = hint ? hint : grub_strlen (str);
  297. if (parser->lexerstate->used + len >= parser->lexerstate->size)
  298. {
  299. size = len * 2;
  300. if (size < parser->lexerstate->size * 2)
  301. size = parser->lexerstate->size * 2;
  302. ptr = grub_realloc (parser->lexerstate->text, size);
  303. if (!ptr)
  304. {
  305. grub_script_yyerror (parser, 0);
  306. return;
  307. }
  308. parser->lexerstate->text = ptr;
  309. parser->lexerstate->size = size;
  310. }
  311. grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
  312. parser->lexerstate->used += len;
  313. }
  314. static int
  315. grub_lexer_resplit (const char *text, yyscan_t yyscanner)
  316. {
  317. /* resplit text */
  318. if (yy_scan_string (text, yyscanner))
  319. {
  320. yyget_extra (yyscanner)->lexerstate->merge_start = 1;
  321. yy_push_state (SPLIT, yyscanner);
  322. return 0;
  323. }
  324. grub_script_yyerror (yyget_extra (yyscanner), 0);
  325. return 1;
  326. }
  327. static int
  328. grub_lexer_unput (const char *text, yyscan_t yyscanner)
  329. {
  330. struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
  331. grub_free (lexerstate->prefix);
  332. lexerstate->prefix = grub_strdup (text);
  333. if (! lexerstate->prefix)
  334. {
  335. grub_script_yyerror (yyget_extra (yyscanner), N_("out of memory"));
  336. return 1;
  337. }
  338. return 0;
  339. }