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 extern oconfig_item_t *ci_root;
33 %}
35 %start entire_file
37 %union {
38 double number;
39 int boolean;
40 char *string;
41 oconfig_value_t cv;
42 oconfig_item_t ci;
43 argument_list_t al;
44 statement_list_t sl;
45 }
47 %token <number> NUMBER
48 %token <boolean> TRUE FALSE
49 %token <string> QUOTED_STRING UNQUOTED_STRING
50 %token SLASH OPENBRAC CLOSEBRAC EOL
52 %type <string> string
53 %type <string> identifier
54 /* arguments */
55 %type <cv> argument
56 %type <al> argument_list
57 /* blocks */
58 %type <ci> block_begin
59 %type <ci> block
60 %type <string> block_end
61 /* statements */
62 %type <ci> option
63 %type <ci> statement
64 %type <sl> statement_list
65 %type <ci> entire_file
67 %%
68 string:
69 QUOTED_STRING {$$ = unquote ($1);}
70 | UNQUOTED_STRING {$$ = strdup ($1);}
71 ;
73 argument:
74 NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
75 | TRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
76 | FALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
77 | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
78 ;
80 argument_list:
81 argument_list argument
82 {
83 $$ = $1;
84 $$.argument_num++;
85 $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
86 $$.argument[$$.argument_num-1] = $2;
87 }
88 | argument
89 {
90 $$.argument = malloc (sizeof (oconfig_value_t));
91 $$.argument[0] = $1;
92 $$.argument_num = 1;
93 }
94 ;
96 identifier:
97 UNQUOTED_STRING {$$ = strdup ($1);}
98 ;
100 option:
101 identifier argument_list EOL
102 {
103 memset (&$$, '\0', sizeof ($$));
104 $$.key = $1;
105 $$.values = $2.argument;
106 $$.values_num = $2.argument_num;
107 }
108 ;
110 block_begin:
111 OPENBRAC identifier CLOSEBRAC EOL
112 {
113 memset (&$$, '\0', sizeof ($$));
114 $$.key = $2;
115 }
116 |
117 OPENBRAC identifier argument_list CLOSEBRAC EOL
118 {
119 memset (&$$, '\0', sizeof ($$));
120 $$.key = $2;
121 $$.values = $3.argument;
122 $$.values_num = $3.argument_num;
123 }
124 ;
126 block_end:
127 OPENBRAC SLASH identifier CLOSEBRAC EOL
128 {
129 $$ = $3;
130 }
131 ;
133 block:
134 block_begin statement_list block_end
135 {
136 if (strcmp ($1.key, $3) != 0)
137 {
138 printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
139 yyerror ("Block not closed..\n");
140 exit (1);
141 }
142 free ($3); $3 = NULL;
143 $$ = $1;
144 $$.children = $2.statement;
145 $$.children_num = $2.statement_num;
146 }
147 ;
149 statement:
150 option {$$ = $1;}
151 | block {$$ = $1;}
152 | EOL {$$.values_num = 0;}
153 ;
155 statement_list:
156 statement_list statement
157 {
158 $$ = $1;
159 if (($2.values_num > 0) || ($2.children_num > 0))
160 {
161 $$.statement_num++;
162 $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
163 $$.statement[$$.statement_num-1] = $2;
164 }
165 }
166 | statement
167 {
168 if (($1.values_num > 0) || ($1.children_num > 0))
169 {
170 $$.statement = malloc (sizeof (oconfig_item_t));
171 $$.statement[0] = $1;
172 $$.statement_num = 1;
173 }
174 else
175 {
176 $$.statement = NULL;
177 $$.statement_num = 0;
178 }
179 }
180 ;
182 entire_file:
183 statement_list
184 {
185 ci_root = malloc (sizeof (oconfig_item_t));
186 memset (ci_root, '\0', sizeof (oconfig_item_t));
187 ci_root->children = $1.statement;
188 ci_root->children_num = $1.statement_num;
189 }
190 ;
192 %%
193 static int yyerror (const char *s)
194 {
195 fprintf (stderr, "Error in line %i near `%s': %s\n", yylineno, yytext, s);
196 return (-1);
197 } /* int yyerror */
199 static char *unquote (const char *orig)
200 {
201 char *ret = strdup (orig);
202 int len;
203 int i;
205 if (ret == NULL)
206 return (NULL);
208 len = strlen (ret);
210 if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
211 return (ret);
213 len -= 2;
214 memmove (ret, ret + 1, len);
215 ret[len] = '\0';
217 for (i = 0; i < len; i++)
218 {
219 if (ret[i] == '\\')
220 {
221 memmove (ret + i, ret + (i + 1), len - i);
222 len--;
223 }
224 }
226 return (ret);
227 } /* char *unquote */