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