1 /**
2 * SysDB - src/liboconfig/parser.y
3 * Based on collectd's oconfig, <http://collectd.org>
4 * Copyright (C) 2007,2008 Florian Forster
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
25 %{
26 #if HAVE_CONFIG_H
27 # include "config.h"
28 #endif /* HAVE_CONFIG_H */
30 #include <stdlib.h>
31 #include <string.h>
32 #include "oconfig.h"
33 #include "aux_types.h"
35 static char *unquote (const char *orig);
36 static int yyerror (const char *s);
38 /* Lexer variables */
39 extern int yylineno;
40 extern char *yytext;
42 /* Lexer functions */
43 int yylex (void);
45 extern oconfig_item_t *ci_root;
46 extern char *c_file;
47 %}
49 %start entire_file
51 %union {
52 double number;
53 int boolean;
54 char *string;
55 oconfig_value_t cv;
56 oconfig_item_t ci;
57 argument_list_t al;
58 statement_list_t sl;
59 }
61 %token <number> NUMBER
62 %token <boolean> BTRUE BFALSE
63 %token <string> QUOTED_STRING UNQUOTED_STRING
64 %token SLASH OPENBRAC CLOSEBRAC EOL
66 %type <string> string
67 %type <string> identifier
68 /* arguments */
69 %type <cv> argument
70 %type <al> argument_list
71 /* blocks */
72 %type <ci> block_begin
73 %type <ci> block
74 %type <string> block_end
75 /* statements */
76 %type <ci> option
77 %type <ci> statement
78 %type <sl> statement_list
79 %type <ci> entire_file
81 /* pass an verbose, specific error message to yyerror() */
82 %error-verbose
84 %%
85 string:
86 QUOTED_STRING {$$ = unquote ($1);}
87 | UNQUOTED_STRING {$$ = strdup ($1);}
88 ;
90 argument:
91 NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
92 | BTRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
93 | BFALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
94 | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
95 ;
97 argument_list:
98 argument_list argument
99 {
100 $$ = $1;
101 $$.argument_num++;
102 $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
103 $$.argument[$$.argument_num-1] = $2;
104 }
105 | argument
106 {
107 $$.argument = malloc (sizeof (oconfig_value_t));
108 $$.argument[0] = $1;
109 $$.argument_num = 1;
110 }
111 ;
113 identifier:
114 UNQUOTED_STRING {$$ = strdup ($1);}
115 ;
117 option:
118 identifier argument_list EOL
119 {
120 memset (&$$, '\0', sizeof ($$));
121 $$.key = $1;
122 $$.values = $2.argument;
123 $$.values_num = $2.argument_num;
124 }
125 ;
127 block_begin:
128 OPENBRAC identifier CLOSEBRAC EOL
129 {
130 memset (&$$, '\0', sizeof ($$));
131 $$.key = $2;
132 }
133 |
134 OPENBRAC identifier argument_list CLOSEBRAC EOL
135 {
136 memset (&$$, '\0', sizeof ($$));
137 $$.key = $2;
138 $$.values = $3.argument;
139 $$.values_num = $3.argument_num;
140 }
141 ;
143 block_end:
144 OPENBRAC SLASH identifier CLOSEBRAC EOL
145 {
146 $$ = $3;
147 }
148 ;
150 block:
151 block_begin statement_list block_end
152 {
153 if (strcmp ($1.key, $3) != 0)
154 {
155 printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
156 yyerror ("Block not closed..\n");
157 exit (1);
158 }
159 free ($3); $3 = NULL;
160 $$ = $1;
161 $$.children = $2.statement;
162 $$.children_num = $2.statement_num;
163 }
164 | block_begin block_end
165 {
166 if (strcmp ($1.key, $2) != 0)
167 {
168 printf ("block_begin = %s; block_end = %s;\n", $1.key, $2);
169 yyerror ("Block not closed..\n");
170 exit (1);
171 }
172 free ($2); $2 = NULL;
173 $$ = $1;
174 $$.children = NULL;
175 $$.children_num = 0;
176 }
177 ;
179 statement:
180 option {$$ = $1;}
181 | block {$$ = $1;}
182 | EOL {$$.values_num = 0;}
183 ;
185 statement_list:
186 statement_list statement
187 {
188 $$ = $1;
189 if (($2.values_num > 0) || ($2.children_num > 0))
190 {
191 $$.statement_num++;
192 $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
193 $$.statement[$$.statement_num-1] = $2;
194 }
195 }
196 | statement
197 {
198 if (($1.values_num > 0) || ($1.children_num > 0))
199 {
200 $$.statement = malloc (sizeof (oconfig_item_t));
201 $$.statement[0] = $1;
202 $$.statement_num = 1;
203 }
204 else
205 {
206 $$.statement = NULL;
207 $$.statement_num = 0;
208 }
209 }
210 ;
212 entire_file:
213 statement_list
214 {
215 ci_root = malloc (sizeof (oconfig_item_t));
216 memset (ci_root, '\0', sizeof (oconfig_item_t));
217 ci_root->children = $1.statement;
218 ci_root->children_num = $1.statement_num;
219 }
220 | /* epsilon */
221 {
222 ci_root = malloc (sizeof (oconfig_item_t));
223 memset (ci_root, '\0', sizeof (oconfig_item_t));
224 ci_root->children = NULL;
225 ci_root->children_num = 0;
226 }
227 ;
229 %%
230 static int yyerror (const char *s)
231 {
232 char *text;
234 if (*yytext == '\n')
235 text = "<newline>";
236 else
237 text = yytext;
239 fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n",
240 c_file, yylineno, text, s);
241 return (-1);
242 } /* int yyerror */
244 static char *unquote (const char *orig)
245 {
246 char *ret = strdup (orig);
247 int len;
248 int i;
250 if (ret == NULL)
251 return (NULL);
253 len = strlen (ret);
255 if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
256 return (ret);
258 len -= 2;
259 memmove (ret, ret + 1, len);
260 ret[len] = '\0';
262 for (i = 0; i < len; i++)
263 {
264 if (ret[i] == '\\')
265 {
266 memmove (ret + i, ret + (i + 1), len - i);
267 len--;
268 }
269 }
271 return (ret);
272 } /* char *unquote */