1 /*
2  * Copyright (c) 2001, 2002, 2003, 2004, 2005  Netli, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $Id: ncnf_cr_y.y,v 1.1 2005/05/26 12:08:19 vlm Exp $
27  */
28 %{
29 
30 #undef	NDEBUG
31 #include "headers.h"
32 #include "ncnf_int.h"
33 #include "ncnf.h"
34 
35 #define	YYPARSE_PARAM	paramp
36 
37 int yylex(void);
38 int yyerror(char *s);
39 
40 extern int __ncnf_cr_lineno;
41 
42 #define	RELAXED_NS		((int)*((void **)YYPARSE_PARAM+1))
43 #define	ALLOC_NOBJ(_class)	_ncnf_obj_new(0, _class, NULL, NULL, __ncnf_cr_lineno)
44 
45 
46 /*
47  * Quick wrapper around object attachment.
48  */
49 #define	ATTACH_OBJ(dst,src) do {				\
50 		if(_ncnf_attach_obj(dst, src, RELAXED_NS)) {	\
51 			int lineno = src->config_line;		\
52 			_ncnf_obj_destroy(src);			\
53 			_ncnf_obj_destroy(dst);			\
54 			dst = NULL;				\
55 			if(errno == EEXIST) {			\
56 			__ncnf_cr_lineno = lineno;		\
57 			yyerror("Similarly named entity already defined"); \
58 			}					\
59 			YYABORT;				\
60 		}						\
61 	} while(0)
62 
63 %}
64 
65 /*
66  * Token value definition
67  */
68 %union {
69 	int tv_int;
70 	bstr_t tv_str;
71 	struct ncnf_obj_s *tv_obj;
72 }
73 
74 /*
75  * Token types returned by scanner
76  */
77 %token	<tv_str>	TOK_NAME
78 %token	<tv_str>	TOK_STRING
79 
80 /*
81  * Reserved words
82  */
83 %token		ERROR
84 %token		AT
85 %token		SEMICOLON
86 %token		INSERT INHERIT REF ATTACH
87 
88 
89 %type	<tv_obj>	sequence
90 %type	<tv_obj>	block
91 %type	<tv_obj>	object
92 %type	<tv_obj>	attribute
93 %type	<tv_obj>	insertion
94 %type	<tv_obj>	reference
95 %type	<tv_obj>	entity
96 %type	<tv_int>	reftype
97 
98 %%
99 cfg_file: {
100 		**(void ***)YYPARSE_PARAM = ALLOC_NOBJ(NOBJ_ROOT);
101 		if(**(void ***)YYPARSE_PARAM == NULL)
102 			YYABORT;
103 	}
104 	| sequence {
105 		struct ncnf_obj_s *param_value = NULL;
106 
107 		if($1 == NULL) {
108 			errno = EINVAL;
109 			YYABORT;
110 		}
111 
112 		if($1->obj_class == NOBJ_ROOT) {
113 			param_value = $1;
114 		} else {
115 			param_value = ALLOC_NOBJ(NOBJ_ROOT);
116 			if(param_value == NULL) {
117 				_ncnf_obj_destroy($1);
118 				YYABORT;
119 			} else {
120 				ATTACH_OBJ(param_value, $1);
121 			}
122 		}
123 
124 		/* Propagate root up to the caller */
125 		**(void ***)YYPARSE_PARAM = param_value;
126 	}
127 	;
128 
129 ps:
130 	| SEMICOLON;
131 
132 sequence: block ps {
133 		if($1 == NULL) {
134 			$$ = NULL;
135 			yyclearin;
136 			yyerrok;
137 			break;
138 		}
139 
140 		$$ = ALLOC_NOBJ(NOBJ_ROOT);
141 		if($$ == NULL) {
142 			_ncnf_obj_destroy($1);
143 			$1 = NULL;
144 			$$ = NULL;
145 			YYABORT;
146 		} else {
147 			ATTACH_OBJ($$, $1);
148 		}
149 	}
150 	| sequence block ps {
151 
152 		$$ = NULL;
153 		if($1 == NULL) {
154 			if($2) _ncnf_obj_destroy($2);
155 			break;
156 		} else if($2 == NULL) {
157 			if($1) _ncnf_obj_destroy($1);
158 			break;
159 		}
160 
161 		if($1->obj_class == NOBJ_ROOT) {
162 			$$ = $1;
163 
164 			ATTACH_OBJ($$, $2);
165 		} else {
166 			$$ = ALLOC_NOBJ(NOBJ_ROOT);
167 			if($$ == NULL) {
168 				_ncnf_obj_destroy($1);
169 				_ncnf_obj_destroy($2);
170 				$$ = NULL;
171 				YYABORT;
172 			}
173 
174 			/* Join two blocks under root */
175 
176 			/* Insert a nested object 1 */
177 			if(_ncnf_attach_obj($$, $1, RELAXED_NS)) {
178 				_ncnf_obj_destroy($1);
179 				_ncnf_obj_destroy($2);	/* Don't forget */
180 				_ncnf_obj_destroy($$);
181 				$$ = NULL;
182 				if(errno == EEXIST)
183 					yyerror("Similarly named entity "
184 						"already defined");
185 				YYABORT;
186 			} else {
187 				/* Insert object 2 */
188 				ATTACH_OBJ($$, $2);
189 			}
190 		}
191 	}
192 	;
193 
194 block:
195 	object { $$ = $1; }
196 	| attribute SEMICOLON { $$ = $1; }
197 	| insertion SEMICOLON { $$ = $1; }
198 	| reference SEMICOLON { $$ = $1; }
199 	;
200 
201 object:
202 	entity '{' '}' {
203 		$$ = $1;
204 		if($$) {
205 			$$->obj_class = NOBJ_COMPLEX;
206 		}
207 	}
208 	| entity '{' sequence '}' {
209 		int c;
210 
211 		$$ = NULL;
212 		if($1 == NULL) {
213 			if($3) _ncnf_obj_destroy($3);
214 			break;
215 		} else if($3 == NULL) {
216 			if($1) _ncnf_obj_destroy($1);
217 			break;
218 		}
219 
220 		assert($3->obj_class == NOBJ_ROOT);
221 
222 		$$ = $1;
223 		$$->obj_class = NOBJ_COMPLEX;
224 
225 		for(c = 0; c < MAX_COLLECTIONS; c++) {
226 			collection_t *coll_to = &($$)->m_collection[c];
227 			collection_t *coll_from = &($3)->m_collection[c];
228 			if(_ncnf_coll_join(($$)->mr,
229 				coll_to, coll_from, $$,
230 				(RELAXED_NS ? MERGE_NOFLAGS : MERGE_DUPCHECK)
231 				| MERGE_EMPTYSRC))
232 				break;
233 		}
234 
235 		/* Dispose the NCNF_ROOT wrapper around $3 */
236 		_ncnf_obj_destroy($3);
237 
238 		if(c < MAX_COLLECTIONS) {
239 			_ncnf_obj_destroy($$);
240 			$$ = NULL;
241 			YYABORT;
242 		}
243 	}
244 	;
245 
246 attribute:
247 	entity {
248 		$$ = $1;
249 		if($$) {
250 			$$->obj_class = NOBJ_ATTRIBUTE;
251 		}
252 	}
253 	| TOK_NAME '=' TOK_NAME {
254 		$$ = ALLOC_NOBJ(NOBJ_ATTRIBUTE);
255 		if($$) {
256 			$$->type = bstr_ref($1);
257 			$$->value = bstr_ref($3);
258 			$$->m_attr_flags |= 1;
259 		} else {
260 			YYABORT;
261 		}
262 	}
263 	;
264 
265 insertion:
266 	INSERT entity {
267 		$$ = $2;
268 		if($$) {
269 			$$->obj_class = NOBJ_INSERTION;
270 		}
271 	}
272 	| INHERIT entity {
273 		$$ = $2;
274 		if($$) {
275 			$$->obj_class = NOBJ_INSERTION;
276 			$$->m_insert_flags |= 1;
277 		}
278 	}
279 	;
280 
281 reference:
282 	reftype TOK_NAME TOK_STRING '=' TOK_NAME TOK_STRING {
283 		$$ = ALLOC_NOBJ(NOBJ_REFERENCE);
284 		if($$) {
285 			$$->type = bstr_ref($2);
286 			$$->value = bstr_ref($3);
287 			$$->m_ref_type = bstr_ref($5);
288 			$$->m_ref_value = bstr_ref($6);
289 			$$->m_ref_flags = $1;
290 		} else {
291 			YYABORT;
292 		}
293 	}
294 	| reftype TOK_NAME '=' TOK_NAME TOK_STRING {
295 		$$ = ALLOC_NOBJ(NOBJ_REFERENCE);
296 		if($$) {
297 			$$->type = bstr_ref($2);
298 			$$->value = bstr_ref($5);
299 			$$->m_ref_type = bstr_ref($4);
300 			$$->m_ref_value = bstr_ref($5);
301 			$$->m_ref_flags = $1;
302 		} else {
303 			YYABORT;
304 		}
305 	}
306 	| reftype '=' TOK_NAME TOK_STRING {
307                 $$ = ALLOC_NOBJ(NOBJ_REFERENCE);
308                 if($$) {
309                         $$->type = bstr_ref($3);
310                         $$->value = bstr_ref($4);
311                         $$->m_ref_type = bstr_ref($3);
312                         $$->m_ref_value = bstr_ref($4);
313                         $$->m_ref_flags = $1;
314                 } else {
315 			YYABORT;
316                 }
317 	}
318 	| reftype TOK_NAME TOK_STRING '=' TOK_STRING {
319                 $$ = ALLOC_NOBJ(NOBJ_REFERENCE);
320                 if($$) {
321                         $$->type = bstr_ref($2);
322                         $$->value = bstr_ref($3);
323                         $$->m_ref_type = bstr_ref($2);
324                         $$->m_ref_value = bstr_ref($5);
325                         $$->m_ref_flags = $1;
326                 } else {
327 			YYABORT;
328                 }
329 	}
330 	;
331 
332 reftype:
333 	REF {
334 		$$ = 0;
335 	}
336 	| ATTACH {
337 		$$ = 1;
338 	}
339 	;
340 
341 entity:
342 	TOK_NAME TOK_STRING {
343 		$$ = ALLOC_NOBJ(-2);
344 		if($$) {
345 			$$->type = bstr_ref($1);
346 			$$->value = bstr_ref($2);
347 		} else {
348 			YYABORT;
349 		}
350 	}
351 	;
352 
353 
354 %%
355 
356 int
357 yyerror(char *s) {
358 	if(s == NULL) {
359 		switch(errno) {
360 		case EEXIST:
361 			s = "Entity already defined this context";
362 			break;
363 		default:
364 			s = strerror(errno);
365 		}
366 	}
367 
368 	_ncnf_debug_print(1,
369 		"Config parse error near line %d: %s",
370 		__ncnf_cr_lineno, s);
371 	return -1;
372 };
373 
374