discover/grub2: improve handling of word & delimiter tokens
[petitboot] / discover / grub2 / grub2-lexer.l
1
2 %{
3 #include "grub2.h"
4 #include "grub2-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
21 %x sqstring
22 %x dqstring
23
24 WORD    [^{}|&$;<> \t\n'"#]+
25 DELIM   [ \t]+
26 VARNAME ([[:alpha:]][_[:alnum:]]*|[0-9]|[\?@\*#])
27
28 %%
29
30  /* discard whitespace, unless we're looking for inter-word delimiters */
31 {DELIM}      { if (yyget_extra(yyscanner)->inter_word) return TOKEN_DELIM; }
32
33  /* reserved words */
34 "[["         return TOKEN_LDSQBRACKET;
35 "]]"         return TOKEN_RDSQBRACKET;
36 "case"       return TOKEN_CASE;
37 "do"         return TOKEN_DO;
38 "done"       return TOKEN_DONE;
39 "elif"       return TOKEN_ELIF;
40 "else"       return TOKEN_ELSE;
41 "esac"       return TOKEN_ESAC;
42 "fi"         return TOKEN_FI;
43 "for"        return TOKEN_FOR;
44 "function"   return TOKEN_FUNCTION;
45 "if"         return TOKEN_IF;
46 "in"         return TOKEN_IN;
47 "menuentry"  return TOKEN_MENUENTRY;
48 "select"     return TOKEN_SELECT;
49 "submenu"    return TOKEN_SUBMENU;
50 "then"       return TOKEN_THEN;
51 "time"       return TOKEN_TIME;
52 "until"      return TOKEN_UTIL;
53 "while"      return TOKEN_WHILE;
54
55  /* anything that's not a metachar: return as a plain word */
56 {WORD}  {
57                 yylval->word = create_word_text(yyget_extra(yyscanner), yytext);
58                 yyget_extra(yyscanner)->inter_word = true;
59                 return TOKEN_WORD;
60         }
61
62 \${VARNAME} |
63 \$\{{VARNAME}\} {
64                 if (yytext[1] == '{') {
65                         yytext[yyleng-1] = '\0';
66                         yytext++;
67                 }
68                 yytext++;
69                 yylval->word = create_word_var(yyget_extra(yyscanner), yytext,
70                                                 true);
71                 yyget_extra(yyscanner)->inter_word = true;
72                 return TOKEN_WORD;
73         }
74
75  /* single-quoted strings: return a single, non-expanded word token */
76 \'      {
77                 yy_push_state(sqstring, yyscanner);
78         }
79 <sqstring>\' {
80                 yy_pop_state(yyscanner);
81         }
82 <sqstring>[^']+ {
83                 yylval->word = create_word_text(yyget_extra(yyscanner), yytext);
84                 yyget_extra(yyscanner)->inter_word = true;
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                 yyget_extra(yyscanner)->inter_word = true;
98                 return TOKEN_WORD;
99         }
100 <dqstring>\${VARNAME} |
101 <dqstring>\$\{{VARNAME}\} {
102                 if (yytext[1] == '{') {
103                         yytext[yyleng-1] = '\0';
104                         yytext++;
105                 }
106                 yytext++;
107                 yylval->word = create_word_var(yyget_extra(yyscanner), yytext,
108                                                 false);
109                 yyget_extra(yyscanner)->inter_word = true;
110                 return TOKEN_WORD;
111         }
112
113
114
115  /* blocks */
116 "{"     { yyget_extra(yyscanner)->inter_word = false; return '{'; }
117 "}"     { yyget_extra(yyscanner)->inter_word = false; return '}'; }
118
119  /* end-of-line */
120 [ \t]*(;|\n)[ \t]*      {
121                 yyget_extra(yyscanner)->inter_word = false;
122                 return TOKEN_EOL;
123         }
124
125  /* strip comments */
126 #.*     ;
127
128 .       {
129                 yyerror(yyget_extra(yyscanner), yyscanner,
130                                 "unknown token '%s'\n", yytext);
131                 yyterminate();
132         }
133
134 %%
135
136 struct grub2_parser;
137
138 void *yyalloc(size_t bytes, void *yyscanner)
139 {
140         struct grub2_parser *parser = yyget_extra(yyscanner);
141         return talloc_size(parser, bytes);
142 }
143
144 void *yyrealloc(void *ptr, size_t bytes, void *yyscanner)
145 {
146         struct grub2_parser *parser = yyget_extra(yyscanner);
147         return talloc_realloc_size(parser, ptr, bytes);
148 }
149
150 void yyfree(void *ptr, void *yyscanner __attribute__((unused)))
151 {
152         talloc_free(ptr);
153 }