1 /**
2 * oconfig - src/parser.y
3 * Copyright (C) 2007 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 extern char *c_file;
34 %}
36 %start entire_file
38 %union {
39 double number;
40 int boolean;
41 char *string;
42 oconfig_value_t cv;
43 oconfig_item_t ci;
44 argument_list_t al;
45 statement_list_t sl;
46 }
48 %token <number> NUMBER
49 %token <boolean> TRUE FALSE
50 %token <string> QUOTED_STRING UNQUOTED_STRING
51 %token SLASH OPENBRAC CLOSEBRAC EOL
53 %type <string> string
54 %type <string> identifier
55 /* arguments */
56 %type <cv> argument
57 %type <al> argument_list
58 /* blocks */
59 %type <ci> block_begin
60 %type <ci> block
61 %type <string> block_end
62 /* statements */
63 %type <ci> option
64 %type <ci> statement
65 %type <sl> statement_list
66 %type <ci> entire_file
68 /* pass an verbose, specific error message to yyerror() */
69 %error-verbose
71 %%
72 string:
73 QUOTED_STRING {$$ = unquote ($1);}
74 | UNQUOTED_STRING {$$ = strdup ($1);}
75 ;
77 argument:
78 NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
79 | TRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
80 | FALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
81 | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
82 ;
84 argument_list:
85 argument_list argument
86 {
87 $$ = $1;
88 $$.argument_num++;
89 $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
90 $$.argument[$$.argument_num-1] = $2;
91 }
92 | argument
93 {
94 $$.argument = malloc (sizeof (oconfig_value_t));
95 $$.argument[0] = $1;
96 $$.argument_num = 1;
97 }
98 ;
100 identifier:
101 UNQUOTED_STRING {$$ = strdup ($1);}
102 ;
104 option:
105 identifier argument_list EOL
106 {
107 memset (&$$, '\0', sizeof ($$));
108 $$.key = $1;
109 $$.values = $2.argument;
110 $$.values_num = $2.argument_num;
111 }
112 ;
114 block_begin:
115 OPENBRAC identifier argument_list CLOSEBRAC EOL
116 {
117 memset (&$$, '\0', sizeof ($$));
118 $$.key = $2;
119 $$.values = $3.argument;
120 $$.values_num = $3.argument_num;
121 }
122 ;
124 block_end:
125 OPENBRAC SLASH identifier CLOSEBRAC EOL
126 {
127 $$ = $3;
128 }
129 ;
131 block:
132 block_begin statement_list block_end
133 {
134 if (strcmp ($1.key, $3) != 0)
135 {
136 printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
137 yyerror ("Block not closed..\n");
138 exit (1);
139 }
140 free ($3); $3 = NULL;
141 $$ = $1;
142 $$.children = $2.statement;
143 $$.children_num = $2.statement_num;
144 }
145 ;
147 statement:
148 option {$$ = $1;}
149 | block {$$ = $1;}
150 | EOL {$$.values_num = 0;}
151 ;
153 statement_list:
154 statement_list statement
155 {
156 $$ = $1;
157 if ($2.values_num > 0)
158 {
159 $$.statement_num++;
160 $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
161 $$.statement[$$.statement_num-1] = $2;
162 }
163 }
164 | statement
165 {
166 if ($1.values_num > 0)
167 {
168 $$.statement = malloc (sizeof (oconfig_item_t));
169 $$.statement[0] = $1;
170 $$.statement_num = 1;
171 }
172 else
173 {
174 $$.statement = NULL;
175 $$.statement_num = 0;
176 }
177 }
178 ;
180 entire_file:
181 statement_list
182 {
183 ci_root = malloc (sizeof (oconfig_item_t));
184 memset (ci_root, '\0', sizeof (oconfig_item_t));
185 ci_root->children = $1.statement;
186 ci_root->children_num = $1.statement_num;
187 }
188 ;
190 %%
191 static int yyerror (const char *s)
192 {
193 char *text;
195 if (*yytext == '\n')
196 text = "<newline>";
197 else
198 text = yytext;
200 fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n",
201 c_file, yylineno, text, s);
202 return (-1);
203 } /* int yyerror */
205 static char *unquote (const char *orig)
206 {
207 char *ret = strdup (orig);
208 int len;
209 int i;
211 if (ret == NULL)
212 return (NULL);
214 len = strlen (ret);
216 if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
217 return (ret);
219 ret++;
220 len -= 2;
221 ret[len] = '\0';
223 for (i = 0; i < len; i++)
224 {
225 if (ret[i] == '\\')
226 {
227 memmove (ret + i, ret + (i + 1), len - i);
228 len--;
229 }
230 }
232 return (ret);
233 } /* char *unquote */