parser.y: Fix segfaults due to wrong allocation size.
[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 void dump_ci (oconfig_item_t *ci, int shift);
21 %}
22
23 %start entire_file
24
25 %union {
26         double  number;
27         int     boolean;
28         char   *string;
29         oconfig_value_t  cv;
30         oconfig_item_t   ci;
31         argument_list_t  al;
32         statement_list_t sl;
33 }
34
35 %token <number> NUMBER
36 %token <boolean> TRUE FALSE
37 %token <string> QUOTED_STRING UNQUOTED_STRING
38 %token SLASH OPENBRAC CLOSEBRAC EOL
39
40 %type <string> string
41 %type <string> identifier
42 /* arguments */
43 %type <cv> argument
44 %type <al> argument_list
45 /* blocks */
46 %type <ci> block_begin
47 %type <ci> block
48 %type <string> block_end
49 /* statements */
50 %type <ci> option
51 %type <ci> statement
52 %type <sl> statement_list
53
54 %%
55 string:
56         QUOTED_STRING           {$$ = $1;}
57         | UNQUOTED_STRING       {$$ = $1;}
58         ;
59
60 argument:
61         NUMBER                  {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
62         | TRUE                  {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
63         | FALSE                 {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
64         | string                {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
65         ;
66
67 argument_list:
68         argument_list argument
69         {
70          $$ = $1;
71          $$.argument_num++;
72          $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
73          $$.argument[$$.argument_num-1] = $2;
74         }
75         | argument
76         {
77          $$.argument = malloc (sizeof (oconfig_value_t));
78          $$.argument[0] = $1;
79          $$.argument_num = 1;
80         }
81         ;
82
83 identifier:
84         UNQUOTED_STRING                 {$$ = $1;}
85         ;
86
87 option:
88         identifier argument_list EOL
89         {
90          memset (&$$, '\0', sizeof ($$));
91          $$.key = $1;
92          $$.values = $2.argument;
93          $$.values_num = $2.argument_num;
94         }
95         ;
96
97 block_begin:
98         OPENBRAC identifier argument_list CLOSEBRAC EOL
99         {
100          memset (&$$, '\0', sizeof ($$));
101          $$.key = $2;
102          $$.values = $3.argument;
103          $$.values_num = $3.argument_num;
104         }
105         ;
106
107 block_end:
108         OPENBRAC SLASH identifier CLOSEBRAC EOL
109         {
110          $$ = $3;
111         }
112         ;
113
114 block:
115         block_begin statement_list block_end
116         {
117          if (strcmp ($1.key, $3) != 0)
118                 yyerror ("Block %s not closed..\n", $1);
119          $$ = $1;
120          $$.children = $2.statement;
121          $$.children_num = $2.statement_num;
122         }
123         ;
124
125 statement:
126         option          {$$ = $1;}
127         | block         {$$ = $1;}
128         | EOL           {/* ignore */}
129         ;
130
131 statement_list:
132         statement_list statement
133         {
134          $$ = $1;
135          $$.statement_num++;
136          $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
137          $$.statement[$$.statement_num-1] = $2;
138         }
139         | statement
140         {
141          $$.statement = malloc (sizeof (oconfig_item_t));
142          $$.statement[0] = $1;
143          $$.statement_num = 1;
144         }
145         ;
146
147 entire_file:
148         statement_list
149         {
150          int i;
151          for (i = 0; i < $1.statement_num; i++)
152                 dump_ci ($1.statement + i, 0);
153         }
154         ;
155
156 %%
157 #include "lex.yy.c"
158
159 /*
160 void yyerror (char *s)
161 {
162         fprintf (stderr, "%s\n", s);
163 }
164
165 int yylex (void)
166 {
167         return (getc (stdin));
168 }
169 */
170
171 int main (int argc, char **argv)
172 {
173         yyparse ();
174         return (0);
175 }
176
177 static void dump_ci (oconfig_item_t *ci, int shift)
178 {
179         int i;
180
181         if (shift > 0)
182                 printf ("%*s", shift, "");
183
184         printf ("%s", ci->key);
185         for (i = 0; i < ci->values_num; i++)
186         {
187                 oconfig_value_t cv = ci->values[i];
188
189                 if (cv.type == OCONFIG_TYPE_STRING)
190                         printf (" `%s'", cv.value.string);
191                 else if (cv.type == OCONFIG_TYPE_NUMBER)
192                         printf (" %lf", cv.value.number);
193                 else if (cv.type == OCONFIG_TYPE_BOOLEAN)
194                         printf (" %s", cv.value.boolean ? "true" : "false");
195                 else
196                         printf ("<unknown type %i>", cv.type);
197         }
198         printf ("\n");
199
200         for (i = 0; i < ci->children_num; i++)
201                 dump_ci (ci->children + i, shift + 1);
202 }