discover/grub2: Clean up error-handling for grub2 parser & lexer
[petitboot] / discover / grub2 / lexer.l
1
2 %{
3 #include "grub2.h"
4 #include "parser.h"
5 #include <talloc/talloc.h>
6
7 void yyerror(struct grub2_parser *parser, const char *fmt, ...);
8 %}
9
10 %option nounput noinput
11 %option batch never-interactive
12 %option warn
13 %option noyywrap
14 %option stack noyy_top_state
15 %option reentrant
16 %option bison-bridge
17 %option yylineno
18 %option noyyalloc noyyfree noyyrealloc
19 %option extra-type="struct grub2_parser *"
20 %option header-file="lexer.h"
21 %option outfile="lexer.c"
22
23 %x sqstring
24 %x dqstring
25
26 WORD    [^{}|&$;<> \t\n'"#]+
27 VARNAME ([[:alpha:]][_[:alnum:]]*|[0-9]|[\?@\*#])
28
29 %%
30
31  /* discard leading & trailing whitespace, but keep inter-word delimeters */
32 ^[ \t]+ ;
33 [ \t]+$ ;
34 [ \t]+  return TOKEN_DELIM;
35
36  /* reserved words */
37 "[["         return TOKEN_LDSQBRACKET;
38 "]]"         return TOKEN_RDSQBRACKET;
39 "case"       return TOKEN_CASE;
40 "do"         return TOKEN_DO;
41 "done"       return TOKEN_DONE;
42 "elif"       return TOKEN_ELIF;
43 "else"       return TOKEN_ELSE;
44 "esac"       return TOKEN_ESAC;
45 "fi"         return TOKEN_FI;
46 "for"        return TOKEN_FOR;
47 "function"   return TOKEN_FUNCTION;
48 "if"         return TOKEN_IF;
49 "in"         return TOKEN_IN;
50 "menuentry"  return TOKEN_MENUENTRY;
51 "select"     return TOKEN_SELECT;
52 "submenu"    return TOKEN_SUBMENU;
53 "then"       return TOKEN_THEN;
54 "time"       return TOKEN_TIME;
55 "until"      return TOKEN_UTIL;
56 "while"      return TOKEN_WHILE;
57
58  /* anything that's not a metachar: return as a plain word */
59 {WORD}  {
60                 yylval->word = create_word_text(yyget_extra(yyscanner), yytext);
61                 return TOKEN_WORD;
62         }
63
64 \${VARNAME} |
65 \$\{{VARNAME}\} {
66                 if (yytext[1] == '{') {
67                         yytext[yyleng-1] = '\0';
68                         yytext++;
69                 }
70                 yytext++;
71                 yylval->word = create_word_var(yyget_extra(yyscanner), yytext,
72                                                 true);
73                 return TOKEN_WORD;
74         }
75
76  /* single-quoted strings: return a single, non-expanded word token */
77 \'      {
78                 yy_push_state(sqstring, yyscanner);
79         }
80 <sqstring>\' {
81                 yy_pop_state(yyscanner);
82         }
83 <sqstring>[^']+ {
84                 yylval->word = create_word_text(yyget_extra(yyscanner), yytext);
85                 return TOKEN_WORD;
86         }
87
88  /* double-quoted strings: return a single, expanded word token */
89 \"      {
90                 yy_push_state(dqstring, yyscanner);
91         }
92 <dqstring>\" {
93                 yy_pop_state(yyscanner);
94         }
95 <dqstring>([^"\$]|\\\")+ {
96                 yylval->word = create_word_text(yyget_extra(yyscanner), yytext);
97                 return TOKEN_WORD;
98         }
99 <dqstring>\${VARNAME} |
100 <dqstring>\$\{{VARNAME}\} {
101                 if (yytext[1] == '{') {
102                         yytext[yyleng-1] = '\0';
103                         yytext++;
104                 }
105                 yytext++;
106                 yylval->word = create_word_var(yyget_extra(yyscanner), yytext,
107                                                 false);
108                 return TOKEN_WORD;
109         }
110
111
112
113  /* blocks */
114 "{"     return '{';
115 "}"     return '}';
116
117  /* end-of-line */
118 [ \t]*(;|\n)[ \t]*      return TOKEN_EOL;
119
120  /* strip comments */
121 #.*     ;
122
123 .       {
124                 yyerror(yyget_extra(yyscanner), "unknown token '%s'\n", yytext);
125                 yyterminate();
126         }
127
128 %%
129
130 struct grub2_parser;
131
132 void *yyalloc(size_t bytes, void *yyscanner)
133 {
134         struct grub2_parser *parser = yyget_extra(yyscanner);
135         return talloc_size(parser, bytes);
136 }
137
138 void *yyrealloc(void *ptr, size_t bytes, void *yyscanner)
139 {
140         struct grub2_parser *parser = yyget_extra(yyscanner);
141         return talloc_realloc_size(parser, ptr, bytes);
142 }
143
144 void yyfree(void *ptr, void *yyscanner __attribute__((unused)))
145 {
146         talloc_free(ptr);
147 }