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