]> git.ipfire.org Git - pakfire.git/blame_incremental - 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
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
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();
37
38extern int num_lines;
39static Pakfire pakfire;
40static void yyerror(const char* s);
41
42static void cleanup(void);
43#define ABORT do { cleanup(); YYABORT; } while (0);
44
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];
48
49char* 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
73top : top thing
74 | thing
75 ;
76
77thing : block
78 | empty
79 ;
80
81empty : WHITESPACE NEWLINE
82 | NEWLINE
83 ;
84
85// Optional whitespace
86whitespace : WHITESPACE
87 | /* empty */
88 ;
89
90variable : WORD
91 {
92 $$ = $1;
93 };
94
95value : words
96 {
97 $$ = $1;
98 }
99 | /* empty */
100 {
101 $$ = NULL;
102 };
103
104words : 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
117line : whitespace words NEWLINE
118 {
119 // Only forward words
120 $$ = $2;
121 }
122 | whitespace NEWLINE {
123 $$ = NULL;
124 };
125
126text : 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
140block_opening : variable NEWLINE
141 {
142 current_block = pakfire_strdup($1);
143 };
144
145block_closing : END NEWLINE
146 {
147 pakfire_free(current_block);
148 current_block = NULL;
149 }
150
151block : block_opening assignments block_closing;
152
153assignments : assignments assignment
154 | assignments empty
155 | /* empty */
156 ;
157
158assignment : 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
173static 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
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
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
223int 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
237void yyerror(const char* s) {
238 ERROR(pakfire, "Error (line %d): %s\n", num_lines, s);
239}