Code

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