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