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