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