1 /*
2  * gram.y
3  *
4  * $Author$
5  * $Date$
6  *
7  * Copyright (C) 2003 why the lucky stiff
8  */
9 
10 %start doc
11 %pure-parser
12 %parse-param {void* parser}
13 %lex-param {void* parser}
14 
15 %{
16 
17 #define YYDEBUG 1
18 #define YYERROR_VERBOSE 1
19 #ifndef YYSTACK_USE_ALLOCA
20 #define YYSTACK_USE_ALLOCA 0
21 #endif
22 
23 #include "syck.h"
24 #include "sycklex.h"
25 
26 void apply_seq_in_map( SyckParser *parser, SyckNode *n );
27 
28 #define NULL_NODE(parser, node) \
29         SyckNode *node = syck_new_str( "", scalar_plain ); \
30         if ( ((SyckParser *)parser)->taguri_expansion == 1 ) \
31         { \
32             node->type_id = syck_taguri( YAML_DOMAIN, "null", 4 ); \
33         } \
34         else \
35         { \
36             node->type_id = syck_strndup( "null", 4 ); \
37         }
38 %}
39 
40 %union {
41     SYMID nodeId;
42     SyckNode *nodeData;
43     char *name;
44 };
45 
46 %token <name>       YAML_ANCHOR YAML_ALIAS YAML_TRANSFER YAML_TAGURI YAML_ITRANSFER
47 %token <nodeData>   YAML_WORD YAML_PLAIN YAML_BLOCK
48 %token              YAML_DOCSEP YAML_IOPEN YAML_INDENT YAML_IEND
49 
50 %type <nodeId>      doc basic_seq
51 %type <nodeData>    atom word_rep ind_rep struct_rep atom_or_empty empty
52 %type <nodeData>    implicit_seq inline_seq implicit_map inline_map inline_seq_atom inline_map_atom
53 %type <nodeData>    top_imp_seq in_implicit_seq in_inline_seq basic_mapping complex_key complex_value
54 %type <nodeData>    top_imp_map in_implicit_map in_inline_map complex_mapping
55 
56 %left               '-' ':'
57 %left               '[' ']' '{' '}' ',' '?'
58 
59 %%
60 
61 doc     : atom
62         {
63            ((SyckParser *)parser)->root = syck_hdlr_add_node( (SyckParser *)parser, $1 );
64         }
65         | YAML_DOCSEP atom_or_empty
66         {
67            ((SyckParser *)parser)->root = syck_hdlr_add_node( (SyckParser *)parser, $2 );
68         }
69         |
70         {
71            ((SyckParser *)parser)->eof = 1;
72         }
73         ;
74 
75 atom	: word_rep
76         | ind_rep
77         ;
78 
79 ind_rep : struct_rep
80         | YAML_TRANSFER ind_rep
81         {
82             syck_add_transfer( $1, $2, ((SyckParser *)parser)->taguri_expansion );
83             $$ = $2;
84         }
85         | YAML_TAGURI ind_rep
86         {
87             syck_add_transfer( $1, $2, 0 );
88             $$ = $2;
89         }
90         | YAML_ANCHOR ind_rep
91         {
92            /*
93             * _Anchors_: The language binding must keep a separate symbol table
94             * for anchors.  The actual ID in the symbol table is returned to the
95             * higher nodes, though.
96             */
97            $$ = syck_hdlr_add_anchor( (SyckParser *)parser, $1, $2 );
98         }
99         | indent_open ind_rep indent_flex_end
100         {
101            $$ = $2;
102         }
103         ;
104 
105 atom_or_empty   : atom
106                 | empty
107                 ;
108 
109 empty           : indent_open empty indent_end
110                 {
111                     $$ = $2;
112                 }
113                 |
114                 {
115                     NULL_NODE( parser, n );
116                     $$ = n;
117                 }
118                 | YAML_ITRANSFER empty
119                 {
120                    if ( ((SyckParser *)parser)->implicit_typing == 1 )
121                    {
122                       try_tag_implicit( $2, ((SyckParser *)parser)->taguri_expansion );
123                    }
124                    $$ = $2;
125                 }
126                 | YAML_TRANSFER empty
127                 {
128                     syck_add_transfer( $1, $2, ((SyckParser *)parser)->taguri_expansion );
129                     $$ = $2;
130                 }
131                 | YAML_TAGURI empty
132                 {
133                     syck_add_transfer( $1, $2, 0 );
134                     $$ = $2;
135                 }
136                 | YAML_ANCHOR empty
137                 {
138                    /*
139                     * _Anchors_: The language binding must keep a separate symbol table
140                     * for anchors.  The actual ID in the symbol table is returned to the
141                     * higher nodes, though.
142                     */
143                    $$ = syck_hdlr_add_anchor( (SyckParser *)parser, $1, $2 );
144                 }
145                 ;
146 
147 /*
148  * Indentation abstractions
149  */
150 indent_open     : YAML_IOPEN
151                 | indent_open YAML_INDENT
152                 ;
153 
154 indent_end      : YAML_IEND
155                 ;
156 
157 indent_sep      : YAML_INDENT
158                 ;
159 
160 indent_flex_end : YAML_IEND
161                 | indent_sep indent_flex_end
162                 ;
163 
164 /*
165  * Words are broken out to distinguish them
166  * as keys in implicit maps and valid elements
167  * for the inline structures
168  */
169 word_rep	: YAML_TRANSFER word_rep
170             {
171                syck_add_transfer( $1, $2, ((SyckParser *)parser)->taguri_expansion );
172                $$ = $2;
173             }
174             | YAML_TAGURI word_rep
175             {
176                syck_add_transfer( $1, $2, 0 );
177                $$ = $2;
178             }
179             | YAML_ITRANSFER word_rep
180             {
181                if ( ((SyckParser *)parser)->implicit_typing == 1 )
182                {
183                   try_tag_implicit( $2, ((SyckParser *)parser)->taguri_expansion );
184                }
185                $$ = $2;
186             }
187             | YAML_ANCHOR word_rep
188             {
189                $$ = syck_hdlr_add_anchor( (SyckParser *)parser, $1, $2 );
190             }
191             | YAML_ALIAS
192             {
193                /*
194                 * _Aliases_: The anchor symbol table is scanned for the anchor name.
195                 * The anchor's ID in the language's symbol table is returned.
196                 */
197                $$ = syck_hdlr_get_anchor( (SyckParser *)parser, $1 );
198             }
199 			| YAML_WORD
200             {
201                SyckNode *n = $1;
202                if ( ((SyckParser *)parser)->taguri_expansion == 1 )
203                {
204                    n->type_id = syck_taguri( YAML_DOMAIN, "str", 3 );
205                }
206                else
207                {
208                    n->type_id = syck_strndup( "str", 3 );
209                }
210                $$ = n;
211             }
212             | YAML_PLAIN
213             | indent_open word_rep indent_flex_end
214             {
215                $$ = $2;
216             }
217             ;
218 
219 /*
220  * Any of these structures can be used as
221  * complex keys
222  */
223 struct_rep	: YAML_BLOCK
224 			| implicit_seq
225 			| inline_seq
226 			| implicit_map
227 			| inline_map
228             ;
229 
230 /*
231  * Implicit sequence
232  */
233 implicit_seq	: indent_open top_imp_seq indent_end
234                 {
235                     $$ = $2;
236                 }
237                 | indent_open in_implicit_seq indent_end
238                 {
239                     $$ = $2;
240                 }
241                 ;
242 
243 basic_seq       : '-' atom_or_empty
244                 {
245                     $$ = syck_hdlr_add_node( (SyckParser *)parser, $2 );
246                 }
247                 ;
248 
249 top_imp_seq     : YAML_TRANSFER indent_sep in_implicit_seq
250                 {
251                     syck_add_transfer( $1, $3, ((SyckParser *)parser)->taguri_expansion );
252                     $$ = $3;
253                 }
254                 | YAML_TRANSFER top_imp_seq
255                 {
256                     syck_add_transfer( $1, $2, ((SyckParser *)parser)->taguri_expansion );
257                     $$ = $2;
258                 }
259                 | YAML_TAGURI indent_sep in_implicit_seq
260                 {
261                     syck_add_transfer( $1, $3, 0 );
262                     $$ = $3;
263                 }
264                 | YAML_TAGURI top_imp_seq
265                 {
266                     syck_add_transfer( $1, $2, 0 );
267                     $$ = $2;
268                 }
269                 | YAML_ANCHOR indent_sep in_implicit_seq
270                 {
271                     $$ = syck_hdlr_add_anchor( (SyckParser *)parser, $1, $3 );
272                 }
273                 | YAML_ANCHOR top_imp_seq
274                 {
275                     $$ = syck_hdlr_add_anchor( (SyckParser *)parser, $1, $2 );
276                 }
277                 ;
278 
279 in_implicit_seq : basic_seq
280                 {
281                     $$ = syck_new_seq( $1 );
282                 }
283 				| in_implicit_seq indent_sep basic_seq
284 				{
285                     syck_seq_add( $1, $3 );
286                     $$ = $1;
287 				}
288 				| in_implicit_seq indent_sep
289 				{
290                     $$ = $1;
291 				}
292                 ;
293 
294 /*
295  * Inline sequences
296  */
297 inline_seq		: '[' in_inline_seq ']'
298                 {
299                     $$ = $2;
300                 }
301 				| '[' ']'
302                 {
303                     $$ = syck_alloc_seq();
304                 }
305                 ;
306 
307 in_inline_seq   : inline_seq_atom
308                 {
309                     $$ = syck_new_seq( syck_hdlr_add_node( (SyckParser *)parser, $1 ) );
310                 }
311                 | in_inline_seq ',' inline_seq_atom
312 				{
313                     syck_seq_add( $1, syck_hdlr_add_node( (SyckParser *)parser, $3 ) );
314                     $$ = $1;
315 				}
316                 ;
317 
318 inline_seq_atom : atom
319                 | basic_mapping
320                 ;
321 
322 /*
323  * Implicit maps
324  */
325 implicit_map	: indent_open top_imp_map indent_end
326                 {
327                     apply_seq_in_map( (SyckParser *)parser, $2 );
328                     $$ = $2;
329                 }
330                 | indent_open in_implicit_map indent_end
331                 {
332                     apply_seq_in_map( (SyckParser *)parser, $2 );
333                     $$ = $2;
334                 }
335                 ;
336 
337 top_imp_map     : YAML_TRANSFER indent_sep in_implicit_map
338                 {
339                     syck_add_transfer( $1, $3, ((SyckParser *)parser)->taguri_expansion );
340                     $$ = $3;
341                 }
342                 | YAML_TRANSFER top_imp_map
343                 {
344                     syck_add_transfer( $1, $2, ((SyckParser *)parser)->taguri_expansion );
345                     $$ = $2;
346                 }
347                 | YAML_TAGURI indent_sep in_implicit_map
348                 {
349                     syck_add_transfer( $1, $3, 0 );
350                     $$ = $3;
351                 }
352                 | YAML_TAGURI top_imp_map
353                 {
354                     syck_add_transfer( $1, $2, 0 );
355                     $$ = $2;
356                 }
357                 | YAML_ANCHOR indent_sep in_implicit_map
358                 {
359                     $$ = syck_hdlr_add_anchor( (SyckParser *)parser, $1, $3 );
360                 }
361                 | YAML_ANCHOR top_imp_map
362                 {
363                     $$ = syck_hdlr_add_anchor( (SyckParser *)parser, $1, $2 );
364                 }
365                 ;
366 
367 complex_key     : word_rep
368                 | '?' atom indent_sep
369                 {
370                     $$ = $2;
371                 }
372                 ;
373 
374 complex_value   : atom_or_empty
375                 ;
376 
377 /* Default needs to be added to SyckSeq i think...
378 				| '=' ':' atom
379 				{
380 					result = [ :DEFAULT, val[2] ]
381 				}
382 */
383 
384 complex_mapping : complex_key ':' complex_value
385                 {
386                     $$ = syck_new_map(
387                         syck_hdlr_add_node( (SyckParser *)parser, $1 ),
388                         syck_hdlr_add_node( (SyckParser *)parser, $3 ) );
389                 }
390 /*
391 				| '?' atom
392                 {
393                     NULL_NODE( parser, n );
394                     $$ = syck_new_map(
395                         syck_hdlr_add_node( (SyckParser *)parser, $2 ),
396                         syck_hdlr_add_node( (SyckParser *)parser, n ) );
397                 }
398 */
399                 ;
400 
401 in_implicit_map : complex_mapping
402 				| in_implicit_map indent_sep basic_seq
403                 {
404                     if ( $1->shortcut == NULL )
405                     {
406                         $1->shortcut = syck_new_seq( $3 );
407                     }
408                     else
409                     {
410                         syck_seq_add( $1->shortcut, $3 );
411                     }
412                     $$ = $1;
413                 }
414 				| in_implicit_map indent_sep complex_mapping
415                 {
416                     apply_seq_in_map( (SyckParser *)parser, $1 );
417                     syck_map_update( $1, $3 );
418                     syck_free_node( $3 );
419                     $3 = NULL;
420                     $$ = $1;
421                 }
422 				| in_implicit_map indent_sep
423                 {
424                     $$ = $1;
425                 }
426                 ;
427 
428 /*
429  * Inline maps
430  */
431 basic_mapping	: atom ':' atom_or_empty
432                 {
433                     $$ = syck_new_map(
434                         syck_hdlr_add_node( (SyckParser *)parser, $1 ),
435                         syck_hdlr_add_node( (SyckParser *)parser, $3 ) );
436                 }
437                 ;
438 
439 inline_map		: '{' in_inline_map '}'
440                 {
441                     $$ = $2;
442                 }
443           		| '{' '}'
444                 {
445                     $$ = syck_alloc_map();
446                 }
447                 ;
448 
449 in_inline_map	: inline_map_atom
450 				| in_inline_map ',' inline_map_atom
451 				{
452                     syck_map_update( $1, $3 );
453                     syck_free_node( $3 );
454                     $3 = NULL;
455                     $$ = $1;
456 				}
457                 ;
458 
459 inline_map_atom : atom
460                 {
461                     NULL_NODE( parser, n );
462                     $$ = syck_new_map(
463                         syck_hdlr_add_node( (SyckParser *)parser, $1 ),
464                         syck_hdlr_add_node( (SyckParser *)parser, n ) );
465                 }
466                 | basic_mapping
467                 ;
468 
469 %%
470 
471 void
472 apply_seq_in_map( SyckParser *parser, SyckNode *n )
473 {
474     long map_len;
475     if ( n->shortcut == NULL )
476     {
477         return;
478     }
479 
480     map_len = syck_map_count( n );
481     syck_map_assign( n, map_value, map_len - 1,
482         syck_hdlr_add_node( parser, n->shortcut ) );
483 
484     n->shortcut = NULL;
485 }
486 
487