1 %{
2 /* MeTA1 configuration parser for Grecs.
3    Copyright (C) 2007-2016 Sergey Poznyakoff
4 
5    Grecs 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; either version 3 of the License, or (at your
8    option) any later version.
9 
10    Grecs is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License along
16    with Grecs. If not, see <http://www.gnu.org/licenses/>. */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <errno.h>
22 #include <string.h>
23 #include "grecs.h"
24 
25 int yylex(void);
26 int yyerror(char const *s);
27 
28 static struct grecs_node *parse_tree;
29 extern int yy_flex_debug;
30 extern void yyset_in(FILE *);
31 %}
32 
33 %error-verbose
34 %locations
35 
36 %union {
37 	char *string;
38 	grecs_value_t svalue, *pvalue;
39 	struct grecs_list *list;
40 	struct { struct grecs_node *head, *tail; } node_list;
41 	struct grecs_node *node;
42 }
43 
44 %token <string> META1_STRING META1_IDENT
45 %type <node> stmt simple block maybe_stmtlist
46 %type <node_list> stmtlist
47 %type <pvalue> tag value
48 %type <string> string slist
49 %type <list> slist0
50 %type <list> values list
51 %%
52 
53 input   : maybe_stmtlist
54           {
55 		  parse_tree = grecs_node_create(grecs_node_root, &@1);
56 		  parse_tree->v.texttab = grecs_text_table();
57 		  grecs_node_bind(parse_tree, $1, 1);
58 	  }
59         ;
60 
61 maybe_stmtlist:
62           /* empty */
63           {
64 		  $$ = NULL;
65 	  }
66         | stmtlist
67 	  {
68 		  $$ = $1.head;
69 	  }
70         ;
71 
72 stmtlist: stmt
73           {
74 		  $$.head = $$.tail = $1;
75 	  }
76         | stmtlist stmt
77           {
78 		  grecs_node_bind($1.tail, $2, 0);
79 	  }
80         ;
81 
82 stmt    : simple
83         | block
84         ;
85 
86 simple  : META1_IDENT '=' value opt_sc
87           {
88 		  $$ = grecs_node_create_points(grecs_node_stmt,
89 						@1.beg, @3.end);
90 		  $$->ident = $1;
91 		  $$->idloc = @1;
92 		  $$->v.value = $3;
93 	  }
94         ;
95 
96 block   : META1_IDENT tag '{' stmtlist '}' opt_sc
97           {
98 		  $$ = grecs_node_create_points(grecs_node_block,
99 						@1.beg, @5.end);
100 		  $$->ident = $1;
101 		  $$->idloc = @1;
102 		  $$->v.value = $2;
103 		  grecs_node_bind($$, $4.head, 1);
104 	  }
105         ;
106 
107 tag     : /* empty */
108           {
109 		  $$ = NULL;
110 	  }
111         | META1_IDENT
112 	  {
113 		  $$ = grecs_malloc(sizeof($$[0]));
114 		  $$->type = GRECS_TYPE_STRING;
115 		  $$->v.string = $1;
116 	  }
117 	;
118 
119 value   : string
120           {
121 		  $$ = grecs_malloc(sizeof($$[0]));
122 		  $$->type = GRECS_TYPE_STRING;
123 		  $$->locus = @1;
124 		  $$->v.string = $1;
125 	  }
126         | list
127           {
128 		  $$ = grecs_malloc(sizeof($$[0]));
129 		  $$->type = GRECS_TYPE_LIST;
130 		  $$->locus = @1;
131 		  $$->v.list = $1;
132 	  }
133         ;
134 
135 string  : META1_IDENT
136         | slist
137         ;
138 
139 slist   : slist0
140           {
141 		  struct grecs_list_entry *ep;
142 
143 		  grecs_line_begin();
144 		  for (ep = $1->head; ep; ep = ep->next) {
145 			  grecs_line_add(ep->data, strlen(ep->data));
146 			  free(ep->data);
147 			  ep->data = NULL;
148 		  }
149 		  $$ = grecs_line_finish();
150 		  grecs_list_free($1);
151 	  }
152 
153 slist0  : META1_STRING
154           {
155 		  $$ = grecs_list_create();
156 		  grecs_list_append($$, $1);
157 	  }
158         | slist0 META1_STRING
159           {
160 		  grecs_list_append($1, $2);
161 		  $$ = $1;
162 	  }
163         ;
164 
165 list    : '{' values '}'
166           {
167 		  $$ = $2;
168 	  }
169         | '{' values ',' '}'
170           {
171 		  $$ = $2;
172 	  }
173         ;
174 
175 values  : value
176           {
177 		  $$ = grecs_value_list_create();
178 		  grecs_list_append($$, $1);
179 	  }
180         | values ',' value
181           {
182 		  grecs_list_append($1, $3);
183 		  $$ = $1;
184 	  }
185         ;
186 
187 opt_sc  : /* empty */
188         | ';'
189         ;
190 
191 %%
192 int
193 yyerror(char const *s)
194 {
195 	grecs_error(&yylloc, 0, "%s", s);
196 	return 0;
197 }
198 
199 struct grecs_node *
grecs_meta1_parser(const char * name,int traceflags)200 grecs_meta1_parser(const char *name, int traceflags)
201 {
202 	int rc;
203 	FILE *fp;
204 
205 	fp = fopen(name, "r");
206 	if (!fp) {
207 		grecs_error(NULL, errno, _("Cannot open `%s'"), name);
208 		return NULL;
209 	}
210 	yyset_in(fp);
211 	yy_flex_debug = traceflags & GRECS_TRACE_LEX;
212 	yydebug = traceflags & GRECS_TRACE_GRAM;
213 	parse_tree = NULL;
214 	grecs_line_acc_create();
215 	rc = yyparse();
216 	fclose(fp);
217 	if (grecs_error_count)
218 		rc = 1;
219 	grecs_line_acc_free();
220 	if (rc) {
221 		grecs_tree_free(parse_tree);
222 		parse_tree = NULL;
223 	}
224 	return parse_tree;
225 }
226 
227