]> git.ipfire.org Git - pakfire.git/blame - 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
CommitLineData
f9a691ef
MT
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%{
4f2a7bce
MT
22#include <stdio.h>
23
a0258b56 24#include <pakfire/logging.h>
23188111 25#include <pakfire/parser.h>
35ebb186 26#include <pakfire/types.h>
23188111 27#include <pakfire/util.h>
35ebb186 28
f9a691ef
MT
29#define YYERROR_VERBOSE 1
30
31typedef struct yy_buffer_state* YY_BUFFER_STATE;
32extern YY_BUFFER_STATE yy_scan_bytes(const char* buffer, size_t len);
33extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
34
35extern int yylex();
36extern int yyparse();
6ab14b96
MT
37
38extern int num_lines;
e98f46a7
MT
39static Pakfire pakfire;
40static void yyerror(const char* s);
6b03e625 41
4f2a7bce
MT
42static void cleanup(void);
43#define ABORT do { cleanup(); YYABORT; } while (0);
44
23188111
MT
45#define NUM_DECLARATIONS 128
46static int pakfire_parser_add_declaration(const char* name, const char* value);
47static struct pakfire_parser_declaration* declarations[NUM_DECLARATIONS];
3b1b9cbd
MT
48
49char* current_block = NULL;
f9a691ef
MT
50%}
51
52%token APPEND
53%token ASSIGN
54%token DEFINE
55%token END
56%token NEWLINE
57%token TAB
f9a691ef 58%token WHITESPACE
6b03e625 59%token <string> WORD
f9a691ef 60
68f7a6f7
MT
61%type <string> line;
62%type <string> text;
28afa9c2
MT
63%type <string> variable;
64%type <string> value;
6b03e625 65%type <string> words;
28afa9c2
MT
66
67%union {
68 char* string;
69}
f9a691ef 70
28afa9c2 71%%
70425a92 72
59f7b7f0
MT
73top : top thing
74 | thing
75 ;
76
77thing : block
28afa9c2 78 | empty
28afa9c2
MT
79 ;
80
81empty : WHITESPACE NEWLINE
82 | NEWLINE
83 ;
84
85// Optional whitespace
86whitespace : WHITESPACE
87 | /* empty */
88 ;
89
6b03e625 90variable : WORD
28afa9c2
MT
91 {
92 $$ = $1;
93 };
94
6b03e625 95value : words
28afa9c2
MT
96 {
97 $$ = $1;
98 }
99 | /* empty */
100 {
101 $$ = NULL;
102 };
103
6b03e625
MT
104words : WORD
105 {
106 $$ = $1;
107 }
68f7a6f7 108 | words WHITESPACE WORD
4f2a7bce
MT
109 {
110 int r = asprintf(&$$, "%s %s", $1, $3);
111 if (r < 0) {
112 ERROR(pakfire, "Could not allocate memory");
113 ABORT;
114 }
de528421 115 };
68f7a6f7
MT
116
117line : whitespace words NEWLINE
118 {
4f2a7bce
MT
119 // Only forward words
120 $$ = $2;
067c6145
MT
121 }
122 | whitespace NEWLINE {
123 $$ = NULL;
68f7a6f7
MT
124 };
125
126text : text line
4f2a7bce
MT
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 }
68f7a6f7 134 | line
de528421
MT
135 | /* empty */
136 {
137 $$ = NULL;
138 };
6b03e625 139
28afa9c2
MT
140block_opening : variable NEWLINE
141 {
3b1b9cbd 142 current_block = pakfire_strdup($1);
28afa9c2
MT
143 };
144
145block_closing : END NEWLINE
146 {
3b1b9cbd
MT
147 pakfire_free(current_block);
148 current_block = NULL;
28afa9c2
MT
149 }
150
3b1b9cbd 151block : block_opening assignments block_closing;
28afa9c2
MT
152
153assignments : assignments assignment
154 | assignments empty
155 | /* empty */
156 ;
157
158assignment : whitespace variable whitespace ASSIGN whitespace value whitespace NEWLINE
159 {
23188111
MT
160 int r = pakfire_parser_add_declaration($2, $6);
161 if (r < 0)
162 ABORT;
eb8fb9a6
MT
163 }
164 | whitespace DEFINE WHITESPACE variable NEWLINE text whitespace END NEWLINE
68f7a6f7 165 {
23188111
MT
166 int r = pakfire_parser_add_declaration($4, $6);
167 if (r < 0)
168 ABORT;
68f7a6f7
MT
169 }
170
f9a691ef
MT
171%%
172
4f2a7bce
MT
173static void cleanup(void) {
174 // Reset Pakfire pointer
175 pakfire = NULL;
23188111
MT
176
177 // Free all declarations
178 for (unsigned int i = 0; i < NUM_DECLARATIONS; i++) {
179 pakfire_free(declarations[i]);
180 }
3b1b9cbd
MT
181
182 // Reset current_block
183 if (current_block) {
184 pakfire_free(current_block);
185 current_block = NULL;
186 }
23188111
MT
187}
188
189static 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
3b1b9cbd
MT
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
23188111
MT
216 d->value = pakfire_strdup(value);
217
218 DEBUG(pakfire, "New declaration: %s = %s\n", d->name, d->value);
219
220 return 0;
4f2a7bce
MT
221}
222
e98f46a7
MT
223int pakfire_parser_parse_metadata(Pakfire _pakfire, const char* data, size_t len) {
224 pakfire = _pakfire;
225
a0258b56
MT
226 DEBUG(pakfire, "Parsing the following data:\n%s\n", data);
227
6ab14b96
MT
228 num_lines = 1;
229
f9a691ef
MT
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
237void yyerror(const char* s) {
e98f46a7 238 ERROR(pakfire, "Error (line %d): %s\n", num_lines, s);
f9a691ef 239}