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