]> git.ipfire.org Git - pakfire.git/blob - src/libpakfire/parser/grammar.y
libpakfire: parser: Do not allow words to be empty (removes a shift/reduce error)
[pakfire.git] / src / libpakfire / parser / grammar.y
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2019 Pakfire development team #
5 # #
6 # This program 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 # This program 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 this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 %{
22 #include <stdio.h>
23
24 #include <pakfire/logging.h>
25 #include <pakfire/parser.h>
26 #include <pakfire/types.h>
27 #include <pakfire/util.h>
28
29 #define YYERROR_VERBOSE 1
30
31 typedef struct yy_buffer_state* YY_BUFFER_STATE;
32 extern YY_BUFFER_STATE yy_scan_bytes(const char* buffer, size_t len);
33 extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
34
35 extern int yylex();
36 extern int yyparse();
37
38 extern int num_lines;
39 static Pakfire pakfire;
40 static void yyerror(const char* s);
41
42 static void cleanup(void);
43 #define ABORT do { cleanup(); YYABORT; } while (0);
44
45 #define NUM_DECLARATIONS 128
46 static int pakfire_parser_add_declaration(const char* name, const char* value);
47 static struct pakfire_parser_declaration* declarations[NUM_DECLARATIONS];
48
49 char* current_block = NULL;
50 %}
51
52 %token APPEND
53 %token ASSIGN
54 %token DEFINE
55 %token END
56 %token NEWLINE
57 %token TAB
58 %token WHITESPACE
59 %token <string> WORD
60
61 %type <string> line;
62 %type <string> text;
63 %type <string> variable;
64 %type <string> value;
65 %type <string> words;
66
67 %union {
68 char* string;
69 }
70
71 %%
72
73 top : top thing
74 | thing
75 ;
76
77 thing : block
78 | empty
79 ;
80
81 empty : WHITESPACE NEWLINE
82 | NEWLINE
83 ;
84
85 // Optional whitespace
86 whitespace : WHITESPACE
87 | /* empty */
88 ;
89
90 variable : WORD
91 {
92 $$ = $1;
93 };
94
95 value : words
96 {
97 $$ = $1;
98 }
99 | /* empty */
100 {
101 $$ = NULL;
102 };
103
104 words : WORD
105 {
106 $$ = $1;
107 }
108 | words WHITESPACE WORD
109 {
110 int r = asprintf(&$$, "%s %s", $1, $3);
111 if (r < 0) {
112 ERROR(pakfire, "Could not allocate memory");
113 ABORT;
114 }
115 };
116
117 line : whitespace words NEWLINE
118 {
119 // Only forward words
120 $$ = $2;
121 }
122 | whitespace NEWLINE {
123 $$ = NULL;
124 };
125
126 text : text line
127 {
128 int r = asprintf(&$$, "%s\n%s", $1, $2);
129 if (r < 0) {
130 ERROR(pakfire, "Could not allocate memory");
131 ABORT;
132 }
133 }
134 | line
135 | /* empty */
136 {
137 $$ = NULL;
138 };
139
140 block_opening : variable NEWLINE
141 {
142 current_block = pakfire_strdup($1);
143 };
144
145 block_closing : END NEWLINE
146 {
147 pakfire_free(current_block);
148 current_block = NULL;
149 }
150
151 block : block_opening assignments block_closing;
152
153 assignments : assignments assignment
154 | assignments empty
155 | /* empty */
156 ;
157
158 assignment : whitespace variable whitespace ASSIGN whitespace value whitespace NEWLINE
159 {
160 int r = pakfire_parser_add_declaration($2, $6);
161 if (r < 0)
162 ABORT;
163 }
164 | whitespace DEFINE WHITESPACE variable NEWLINE text whitespace END NEWLINE
165 {
166 int r = pakfire_parser_add_declaration($4, $6);
167 if (r < 0)
168 ABORT;
169 }
170
171 %%
172
173 static void cleanup(void) {
174 // Reset Pakfire pointer
175 pakfire = NULL;
176
177 // Free all declarations
178 for (unsigned int i = 0; i < NUM_DECLARATIONS; i++) {
179 pakfire_free(declarations[i]);
180 }
181
182 // Reset current_block
183 if (current_block) {
184 pakfire_free(current_block);
185 current_block = NULL;
186 }
187 }
188
189 static int pakfire_parser_add_declaration(const char* name, const char* value) {
190 struct pakfire_parser_declaration* d;
191 unsigned int i = 0;
192
193 while (i++ < NUM_DECLARATIONS && declarations[i])
194 i++;
195
196 if (i == NUM_DECLARATIONS) {
197 ERROR(pakfire, "No free declarations left\n");
198 return -1;
199 }
200
201 // Allocate a new declaration
202 declarations[i] = d = pakfire_calloc(1, sizeof(*d));
203 if (!d)
204 return -1;
205
206 // Import name
207 if (current_block) {
208 int r = asprintf(&d->name, "%s.%s", current_block, name);
209 if (r < 0)
210 return r;
211 } else {
212 d->name = pakfire_strdup(name);
213 }
214
215 // Import value
216 d->value = pakfire_strdup(value);
217
218 DEBUG(pakfire, "New declaration: %s = %s\n", d->name, d->value);
219
220 return 0;
221 }
222
223 int pakfire_parser_parse_metadata(Pakfire _pakfire, const char* data, size_t len) {
224 pakfire = _pakfire;
225
226 DEBUG(pakfire, "Parsing the following data:\n%s\n", data);
227
228 num_lines = 1;
229
230 YY_BUFFER_STATE buffer = yy_scan_bytes(data, len);
231 int r = yyparse();
232 yy_delete_buffer(buffer);
233
234 return r;
235 }
236
237 void yyerror(const char* s) {
238 ERROR(pakfire, "Error (line %d): %s\n", num_lines, s);
239 }