469509d594d4bb1f80d611a0bed6ea7a7e66fce0
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 #include <stdlib.h>
21 #include <string.h>
22 #include "oconfig.h"
23 #include "aux_types.h"
25 static char *unquote (const char *orig);
26 static int yyerror (const char *s);
28 /* Lexer variables */
29 extern int yylineno;
30 extern char *yytext;
32 /* Lexer functions */
33 int yylex (void);
35 extern oconfig_item_t *ci_root;
36 extern char *c_file;
37 %}
39 %start entire_file
41 %union {
42 double number;
43 int boolean;
44 char *string;
45 oconfig_value_t cv;
46 oconfig_item_t ci;
47 argument_list_t al;
48 statement_list_t sl;
49 }
51 %token <number> NUMBER
52 %token <boolean> BTRUE BFALSE
53 %token <string> QUOTED_STRING UNQUOTED_STRING
54 %token SLASH OPENBRAC CLOSEBRAC EOL
56 %type <string> string
57 %type <string> identifier
58 /* arguments */
59 %type <cv> argument
60 %type <al> argument_list
61 /* blocks */
62 %type <ci> block_begin
63 %type <ci> block
64 %type <string> block_end
65 /* statements */
66 %type <ci> option
67 %type <ci> statement
68 %type <sl> statement_list
69 %type <ci> entire_file
71 /* pass an verbose, specific error message to yyerror() */
72 %error-verbose
74 %%
75 string:
76 QUOTED_STRING {$$ = unquote ($1);}
77 | UNQUOTED_STRING {$$ = strdup ($1);}
78 ;
80 argument:
81 NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
82 | BTRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
83 | BFALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
84 | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
85 ;
87 argument_list:
88 argument_list argument
89 {
90 $$ = $1;
91 $$.argument_num++;
92 $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
93 $$.argument[$$.argument_num-1] = $2;
94 }
95 | argument
96 {
97 $$.argument = malloc (sizeof (oconfig_value_t));
98 $$.argument[0] = $1;
99 $$.argument_num = 1;
100 }
101 ;
103 identifier:
104 UNQUOTED_STRING {$$ = strdup ($1);}
105 ;
107 option:
108 identifier argument_list EOL
109 {
110 memset (&$$, '\0', sizeof ($$));
111 $$.key = $1;
112 $$.values = $2.argument;
113 $$.values_num = $2.argument_num;
114 }
115 ;
117 block_begin:
118 OPENBRAC identifier CLOSEBRAC EOL
119 {
120 memset (&$$, '\0', sizeof ($$));
121 $$.key = $2;
122 }
123 |
124 OPENBRAC identifier argument_list CLOSEBRAC EOL
125 {
126 memset (&$$, '\0', sizeof ($$));
127 $$.key = $2;
128 $$.values = $3.argument;
129 $$.values_num = $3.argument_num;
130 }
131 ;
133 block_end:
134 OPENBRAC SLASH identifier CLOSEBRAC EOL
135 {
136 $$ = $3;
137 }
138 ;
140 block:
141 block_begin statement_list block_end
142 {
143 if (strcmp ($1.key, $3) != 0)
144 {
145 printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
146 yyerror ("Block not closed..\n");
147 exit (1);
148 }
149 free ($3); $3 = NULL;
150 $$ = $1;
151 $$.children = $2.statement;
152 $$.children_num = $2.statement_num;
153 }
154 | block_begin block_end
155 {
156 if (strcmp ($1.key, $2) != 0)
157 {
158 printf ("block_begin = %s; block_end = %s;\n", $1.key, $2);
159 yyerror ("Block not closed..\n");
160 exit (1);
161 }
162 free ($2); $2 = NULL;
163 $$ = $1;
164 $$.children = NULL;
165 $$.children_num = 0;
166 }
167 ;
169 statement:
170 option {$$ = $1;}
171 | block {$$ = $1;}
172 | EOL {$$.values_num = 0;}
173 ;
175 statement_list:
176 statement_list statement
177 {
178 $$ = $1;
179 if (($2.values_num > 0) || ($2.children_num > 0))
180 {
181 $$.statement_num++;
182 $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
183 $$.statement[$$.statement_num-1] = $2;
184 }
185 }
186 | statement
187 {
188 if (($1.values_num > 0) || ($1.children_num > 0))
189 {
190 $$.statement = malloc (sizeof (oconfig_item_t));
191 $$.statement[0] = $1;
192 $$.statement_num = 1;
193 }
194 else
195 {
196 $$.statement = NULL;
197 $$.statement_num = 0;
198 }
199 }
200 ;
202 entire_file:
203 statement_list
204 {
205 ci_root = malloc (sizeof (oconfig_item_t));
206 memset (ci_root, '\0', sizeof (oconfig_item_t));
207 ci_root->children = $1.statement;
208 ci_root->children_num = $1.statement_num;
209 }
210 | /* epsilon */
211 {
212 ci_root = malloc (sizeof (oconfig_item_t));
213 memset (ci_root, '\0', sizeof (oconfig_item_t));
214 ci_root->children = NULL;
215 ci_root->children_num = 0;
216 }
217 ;
219 %%
220 static int yyerror (const char *s)
221 {
222 char *text;
224 if (*yytext == '\n')
225 text = "<newline>";
226 else
227 text = yytext;
229 fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n",
230 c_file, yylineno, text, s);
231 return (-1);
232 } /* int yyerror */
234 static char *unquote (const char *orig)
235 {
236 char *ret = strdup (orig);
237 int len;
238 int i;
240 if (ret == NULL)
241 return (NULL);
243 len = strlen (ret);
245 if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
246 return (ret);
248 len -= 2;
249 memmove (ret, ret + 1, len);
250 ret[len] = '\0';
252 for (i = 0; i < len; i++)
253 {
254 if (ret[i] == '\\')
255 {
256 memmove (ret + i, ret + (i + 1), len - i);
257 len--;
258 }
259 }
261 return (ret);
262 } /* char *unquote */