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