1 /**
2 * oconfig - src/parser.y
3 * Copyright (C) 2007,2008 Florian octo Forster <octo at verplant.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
19 %{
20 #if HAVE_CONFIG_H
21 # include "config.h"
22 #endif /* HAVE_CONFIG_H */
24 #include <stdlib.h>
25 #include <string.h>
26 #include "oconfig.h"
27 #include "aux_types.h"
29 static char *unquote (const char *orig);
30 static int yyerror (const char *s);
32 /* Lexer variables */
33 extern int yylineno;
34 extern char *yytext;
36 /* Lexer functions */
37 int yylex (void);
39 extern oconfig_item_t *ci_root;
40 extern char *c_file;
41 %}
43 %start entire_file
45 %union {
46 double number;
47 int boolean;
48 char *string;
49 oconfig_value_t cv;
50 oconfig_item_t ci;
51 argument_list_t al;
52 statement_list_t sl;
53 }
55 %token <number> NUMBER
56 %token <boolean> BTRUE BFALSE
57 %token <string> QUOTED_STRING UNQUOTED_STRING
58 %token SLASH OPENBRAC CLOSEBRAC EOL
60 %type <string> string
61 %type <string> identifier
62 /* arguments */
63 %type <cv> argument
64 %type <al> argument_list
65 /* blocks */
66 %type <ci> block_begin
67 %type <ci> block
68 %type <string> block_end
69 /* statements */
70 %type <ci> option
71 %type <ci> statement
72 %type <sl> statement_list
73 %type <ci> entire_file
75 /* pass an verbose, specific error message to yyerror() */
76 %error-verbose
78 %%
79 string:
80 QUOTED_STRING {$$ = unquote ($1);}
81 | UNQUOTED_STRING {$$ = strdup ($1);}
82 ;
84 argument:
85 NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
86 | BTRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
87 | BFALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
88 | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
89 ;
91 argument_list:
92 argument_list argument
93 {
94 $$ = $1;
95 $$.argument_num++;
96 $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
97 $$.argument[$$.argument_num-1] = $2;
98 }
99 | argument
100 {
101 $$.argument = malloc (sizeof (oconfig_value_t));
102 $$.argument[0] = $1;
103 $$.argument_num = 1;
104 }
105 ;
107 identifier:
108 UNQUOTED_STRING {$$ = strdup ($1);}
109 ;
111 option:
112 identifier argument_list EOL
113 {
114 memset (&$$, '\0', sizeof ($$));
115 $$.key = $1;
116 $$.values = $2.argument;
117 $$.values_num = $2.argument_num;
118 }
119 ;
121 block_begin:
122 OPENBRAC identifier CLOSEBRAC EOL
123 {
124 memset (&$$, '\0', sizeof ($$));
125 $$.key = $2;
126 }
127 |
128 OPENBRAC identifier argument_list CLOSEBRAC EOL
129 {
130 memset (&$$, '\0', sizeof ($$));
131 $$.key = $2;
132 $$.values = $3.argument;
133 $$.values_num = $3.argument_num;
134 }
135 ;
137 block_end:
138 OPENBRAC SLASH identifier CLOSEBRAC EOL
139 {
140 $$ = $3;
141 }
142 ;
144 block:
145 block_begin statement_list block_end
146 {
147 if (strcmp ($1.key, $3) != 0)
148 {
149 printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
150 yyerror ("Block not closed..\n");
151 exit (1);
152 }
153 free ($3); $3 = NULL;
154 $$ = $1;
155 $$.children = $2.statement;
156 $$.children_num = $2.statement_num;
157 }
158 | block_begin block_end
159 {
160 if (strcmp ($1.key, $2) != 0)
161 {
162 printf ("block_begin = %s; block_end = %s;\n", $1.key, $2);
163 yyerror ("Block not closed..\n");
164 exit (1);
165 }
166 free ($2); $2 = NULL;
167 $$ = $1;
168 $$.children = NULL;
169 $$.children_num = 0;
170 }
171 ;
173 statement:
174 option {$$ = $1;}
175 | block {$$ = $1;}
176 | EOL {$$.values_num = 0;}
177 ;
179 statement_list:
180 statement_list statement
181 {
182 $$ = $1;
183 if (($2.values_num > 0) || ($2.children_num > 0))
184 {
185 $$.statement_num++;
186 $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
187 $$.statement[$$.statement_num-1] = $2;
188 }
189 }
190 | statement
191 {
192 if (($1.values_num > 0) || ($1.children_num > 0))
193 {
194 $$.statement = malloc (sizeof (oconfig_item_t));
195 $$.statement[0] = $1;
196 $$.statement_num = 1;
197 }
198 else
199 {
200 $$.statement = NULL;
201 $$.statement_num = 0;
202 }
203 }
204 ;
206 entire_file:
207 statement_list
208 {
209 ci_root = malloc (sizeof (oconfig_item_t));
210 memset (ci_root, '\0', sizeof (oconfig_item_t));
211 ci_root->children = $1.statement;
212 ci_root->children_num = $1.statement_num;
213 }
214 | /* epsilon */
215 {
216 ci_root = malloc (sizeof (oconfig_item_t));
217 memset (ci_root, '\0', sizeof (oconfig_item_t));
218 ci_root->children = NULL;
219 ci_root->children_num = 0;
220 }
221 ;
223 %%
224 static int yyerror (const char *s)
225 {
226 char *text;
228 if (*yytext == '\n')
229 text = "<newline>";
230 else
231 text = yytext;
233 fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n",
234 c_file, yylineno, text, s);
235 return (-1);
236 } /* int yyerror */
238 static char *unquote (const char *orig)
239 {
240 char *ret = strdup (orig);
241 int len;
242 int i;
244 if (ret == NULL)
245 return (NULL);
247 len = strlen (ret);
249 if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
250 return (ret);
252 len -= 2;
253 memmove (ret, ret + 1, len);
254 ret[len] = '\0';
256 for (i = 0; i < len; i++)
257 {
258 if (ret[i] == '\\')
259 {
260 memmove (ret + i, ret + (i + 1), len - i);
261 len--;
262 }
263 }
265 return (ret);
266 } /* char *unquote */