{GPL, other}: Relicense to MIT license.
[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
40 extern oconfig_item_t *ci_root;
41 extern char           *c_file;
42 %}
43
44 %start entire_file
45
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 }
55
56 %token <number> NUMBER
57 %token <boolean> BTRUE BFALSE
58 %token <string> QUOTED_STRING UNQUOTED_STRING
59 %token SLASH OPENBRAC CLOSEBRAC EOL
60
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
75
76 /* pass an verbose, specific error message to yyerror() */
77 %error-verbose
78
79 %%
80 string:
81         QUOTED_STRING           {$$ = unquote ($1);}
82         | UNQUOTED_STRING       {$$ = strdup ($1);}
83         ;
84
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         ;
91
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         ;
107
108 identifier:
109         UNQUOTED_STRING                 {$$ = strdup ($1);}
110         ;
111
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         ;
121
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         ;
137
138 block_end:
139         OPENBRAC SLASH identifier CLOSEBRAC EOL
140         {
141          $$ = $3;
142         }
143         ;
144
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         ;
173
174 statement:
175         option          {$$ = $1;}
176         | block         {$$ = $1;}
177         | EOL           {$$.values_num = 0;}
178         ;
179
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         ;
206
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         ;
223
224 %%
225 static int yyerror (const char *s)
226 {
227         char *text;
228
229         if (*yytext == '\n')
230                 text = "<newline>";
231         else
232                 text = yytext;
233
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 */
238
239 static char *unquote (const char *orig)
240 {
241         char *ret = strdup (orig);
242         int len;
243         int i;
244
245         if (ret == NULL)
246                 return (NULL);
247
248         len = strlen (ret);
249
250         if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
251                 return (ret);
252
253         len -= 2;
254         memmove (ret, ret + 1, len);
255         ret[len] = '\0';
256
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         }
265
266         return (ret);
267 } /* char *unquote */