parser.y 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /* parser.y - The scripting parser. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. %{
  20. #include <grub/script_sh.h>
  21. #include <grub/mm.h>
  22. #define YYFREE grub_free
  23. #define YYMALLOC grub_malloc
  24. #define YYLTYPE_IS_TRIVIAL 0
  25. #define YYENABLE_NLS 0
  26. %}
  27. %union {
  28. struct grub_script_cmd *cmd;
  29. struct grub_script_arglist *arglist;
  30. struct grub_script_arg *arg;
  31. char *string;
  32. }
  33. %token GRUB_PARSER_TOKEN_BAD
  34. %token GRUB_PARSER_TOKEN_EOF 0 "end-of-input"
  35. %token GRUB_PARSER_TOKEN_NEWLINE "\n"
  36. %token GRUB_PARSER_TOKEN_AND "&&"
  37. %token GRUB_PARSER_TOKEN_OR "||"
  38. %token GRUB_PARSER_TOKEN_SEMI2 ";;"
  39. %token GRUB_PARSER_TOKEN_PIPE "|"
  40. %token GRUB_PARSER_TOKEN_AMP "&"
  41. %token GRUB_PARSER_TOKEN_SEMI ";"
  42. %token GRUB_PARSER_TOKEN_LBR "{"
  43. %token GRUB_PARSER_TOKEN_RBR "}"
  44. %token GRUB_PARSER_TOKEN_NOT "!"
  45. %token GRUB_PARSER_TOKEN_LSQBR2 "["
  46. %token GRUB_PARSER_TOKEN_RSQBR2 "]"
  47. %token GRUB_PARSER_TOKEN_LT "<"
  48. %token GRUB_PARSER_TOKEN_GT ">"
  49. %token <arg> GRUB_PARSER_TOKEN_CASE "case"
  50. %token <arg> GRUB_PARSER_TOKEN_DO "do"
  51. %token <arg> GRUB_PARSER_TOKEN_DONE "done"
  52. %token <arg> GRUB_PARSER_TOKEN_ELIF "elif"
  53. %token <arg> GRUB_PARSER_TOKEN_ELSE "else"
  54. %token <arg> GRUB_PARSER_TOKEN_ESAC "esac"
  55. %token <arg> GRUB_PARSER_TOKEN_FI "fi"
  56. %token <arg> GRUB_PARSER_TOKEN_FOR "for"
  57. %token <arg> GRUB_PARSER_TOKEN_IF "if"
  58. %token <arg> GRUB_PARSER_TOKEN_IN "in"
  59. %token <arg> GRUB_PARSER_TOKEN_SELECT "select"
  60. %token <arg> GRUB_PARSER_TOKEN_THEN "then"
  61. %token <arg> GRUB_PARSER_TOKEN_UNTIL "until"
  62. %token <arg> GRUB_PARSER_TOKEN_WHILE "while"
  63. %token <arg> GRUB_PARSER_TOKEN_TIME "time"
  64. %token <arg> GRUB_PARSER_TOKEN_FUNCTION "function"
  65. %token <arg> GRUB_PARSER_TOKEN_MENUENTRY "menuentry"
  66. %token <arg> GRUB_PARSER_TOKEN_NAME "name"
  67. %token <arg> GRUB_PARSER_TOKEN_WORD "word"
  68. %type <arglist> word argument arguments0 arguments1
  69. %type <cmd> script_init script
  70. %type <cmd> grubcmd ifclause ifcmd forcmd whilecmd untilcmd
  71. %type <cmd> command commands1 menuentry statement
  72. %pure-parser
  73. %lex-param { struct grub_parser_param *state };
  74. %parse-param { struct grub_parser_param *state };
  75. %start script_init
  76. %%
  77. /* It should be possible to do this in a clean way... */
  78. script_init: { state->err = 0; } script { state->parsed = $2; state->err = 0; }
  79. ;
  80. script: newlines0
  81. {
  82. $$ = 0;
  83. }
  84. | script statement delimiter newlines0
  85. {
  86. struct grub_script_cmdblock *cmdblock;
  87. cmdblock = (struct grub_script_cmdblock *) $1;
  88. $$ = grub_script_add_cmd (state, cmdblock, $2);
  89. }
  90. | error
  91. {
  92. $$ = 0;
  93. yyerror (state, "Incorrect command");
  94. yyerrok;
  95. }
  96. ;
  97. newlines0: /* Empty */ | newlines1 ;
  98. newlines1: newlines0 "\n" ;
  99. delimiter: ";"
  100. | "\n"
  101. ;
  102. delimiters0: /* Empty */ | delimiters1 ;
  103. delimiters1: delimiter
  104. | delimiters1 "\n"
  105. ;
  106. word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); }
  107. | GRUB_PARSER_TOKEN_WORD { $$ = grub_script_add_arglist (state, 0, $1); }
  108. ;
  109. statement: command { $$ = $1; }
  110. | function { $$ = 0; }
  111. | menuentry { $$ = $1; }
  112. argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); }
  113. | "do" { $$ = grub_script_add_arglist (state, 0, $1); }
  114. | "done" { $$ = grub_script_add_arglist (state, 0, $1); }
  115. | "elif" { $$ = grub_script_add_arglist (state, 0, $1); }
  116. | "else" { $$ = grub_script_add_arglist (state, 0, $1); }
  117. | "esac" { $$ = grub_script_add_arglist (state, 0, $1); }
  118. | "fi" { $$ = grub_script_add_arglist (state, 0, $1); }
  119. | "for" { $$ = grub_script_add_arglist (state, 0, $1); }
  120. | "if" { $$ = grub_script_add_arglist (state, 0, $1); }
  121. | "in" { $$ = grub_script_add_arglist (state, 0, $1); }
  122. | "select" { $$ = grub_script_add_arglist (state, 0, $1); }
  123. | "then" { $$ = grub_script_add_arglist (state, 0, $1); }
  124. | "until" { $$ = grub_script_add_arglist (state, 0, $1); }
  125. | "while" { $$ = grub_script_add_arglist (state, 0, $1); }
  126. | "function" { $$ = grub_script_add_arglist (state, 0, $1); }
  127. | "menuentry" { $$ = grub_script_add_arglist (state, 0, $1); }
  128. | word { $$ = $1; }
  129. ;
  130. arguments0: /* Empty */ { $$ = 0; }
  131. | arguments1 { $$ = $1; }
  132. ;
  133. arguments1: argument arguments0
  134. {
  135. if ($1 && $2)
  136. {
  137. $1->next = $2;
  138. $1->argcount += $2->argcount;
  139. $2->argcount = 0;
  140. }
  141. $$ = $1;
  142. }
  143. ;
  144. grubcmd: word arguments0
  145. {
  146. if ($1 && $2) {
  147. $1->next = $2;
  148. $1->argcount += $2->argcount;
  149. $2->argcount = 0;
  150. }
  151. $$ = grub_script_create_cmdline (state, $1);
  152. }
  153. ;
  154. /* A single command. */
  155. command: grubcmd { $$ = $1; }
  156. | ifcmd { $$ = $1; }
  157. | forcmd { $$ = $1; }
  158. | whilecmd { $$ = $1; }
  159. | untilcmd { $$ = $1; }
  160. ;
  161. /* A list of commands. */
  162. commands1: newlines0 command
  163. {
  164. $$ = grub_script_add_cmd (state, 0, $2);
  165. }
  166. | commands1 delimiters1 command
  167. {
  168. struct grub_script_cmdblock *cmdblock;
  169. cmdblock = (struct grub_script_cmdblock *) $1;
  170. $$ = grub_script_add_cmd (state, cmdblock, $3);
  171. }
  172. ;
  173. function: "function" "name"
  174. {
  175. grub_script_lexer_ref (state->lexerstate);
  176. state->func_mem = grub_script_mem_record (state);
  177. }
  178. delimiters0 "{" commands1 delimiters1 "}"
  179. {
  180. struct grub_script *script;
  181. state->func_mem = grub_script_mem_record_stop (state,
  182. state->func_mem);
  183. script = grub_script_create ($6, state->func_mem);
  184. if (script)
  185. grub_script_function_create ($2, script);
  186. grub_script_lexer_deref (state->lexerstate);
  187. }
  188. ;
  189. menuentry: "menuentry"
  190. {
  191. grub_script_lexer_ref (state->lexerstate);
  192. }
  193. arguments1
  194. {
  195. grub_script_lexer_record_start (state);
  196. }
  197. delimiters0 "{" commands1 delimiters1 "}"
  198. {
  199. char *menu_entry;
  200. menu_entry = grub_script_lexer_record_stop (state);
  201. grub_script_lexer_deref (state->lexerstate);
  202. $$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0);
  203. }
  204. ;
  205. ifcmd: "if"
  206. {
  207. grub_script_lexer_ref (state->lexerstate);
  208. }
  209. ifclause "fi"
  210. {
  211. $$ = $3;
  212. grub_script_lexer_deref (state->lexerstate);
  213. }
  214. ;
  215. ifclause: commands1 delimiters1 "then" commands1 delimiters1
  216. {
  217. $$ = grub_script_create_cmdif (state, $1, $4, 0);
  218. }
  219. | commands1 delimiters1 "then" commands1 delimiters1 "else" commands1 delimiters1
  220. {
  221. $$ = grub_script_create_cmdif (state, $1, $4, $7);
  222. }
  223. | commands1 delimiters1 "then" commands1 delimiters1 "elif" ifclause
  224. {
  225. $$ = grub_script_create_cmdif (state, $1, $4, $7);
  226. }
  227. ;
  228. forcmd: "for" "name"
  229. {
  230. grub_script_lexer_ref (state->lexerstate);
  231. }
  232. "in" arguments0 delimiters1 "do" commands1 delimiters1 "done"
  233. {
  234. $$ = grub_script_create_cmdfor (state, $2, $5, $8);
  235. grub_script_lexer_deref (state->lexerstate);
  236. }
  237. ;
  238. whilecmd: "while"
  239. {
  240. grub_script_lexer_ref (state->lexerstate);
  241. }
  242. commands1 delimiters1 "do" commands1 delimiters1 "done"
  243. {
  244. $$ = grub_script_create_cmdwhile (state, $3, $6, 0);
  245. grub_script_lexer_deref (state->lexerstate);
  246. }
  247. ;
  248. untilcmd: "until"
  249. {
  250. grub_script_lexer_ref (state->lexerstate);
  251. }
  252. commands1 delimiters1 "do" commands1 delimiters1 "done"
  253. {
  254. $$ = grub_script_create_cmdwhile (state, $3, $6, 1);
  255. grub_script_lexer_deref (state->lexerstate);
  256. }
  257. ;