1 /* -*- mode: C -*- */ 2 /* ---------------------------------------------------------------------------- 3 libconfig - A library for processing structured configuration files 4 Copyright (C) 2005-2018 Mark A Lindner 5 6 This file is part of libconfig. 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Lesser General Public License 10 as published by the Free Software Foundation; either version 2.1 of 11 the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Library General Public 19 License along with this library; if not, see 20 <http://www.gnu.org/licenses/>. 21 ---------------------------------------------------------------------------- 22 */ 23 24 %defines 25 %output "y.tab.c" 26 %pure-parser 27 %lex-param{void *scanner} 28 %parse-param{void *scanner} 29 %parse-param{struct parse_context *ctx} 30 %parse-param{struct scan_context *scan_ctx} 31 32 %{ 33 #include <string.h> 34 #include <stdlib.h> 35 36 #include "libconfig.h" 37 #include "parsectx.h" 38 #include "scanctx.h" 39 #include "util.h" 40 #include "wincompat.h" 41 42 /* These declarations are provided to suppress compiler warnings. */ 43 extern int libconfig_yylex(); 44 extern int libconfig_yyget_lineno(); 45 46 static const char *err_array_elem_type = "mismatched element type in array"; 47 static const char *err_duplicate_setting = "duplicate setting name"; 48 49 #define IN_ARRAY() \ 50 (ctx->parent && (ctx->parent->type == CONFIG_TYPE_ARRAY)) 51 52 #define IN_LIST() \ 53 (ctx->parent && (ctx->parent->type == CONFIG_TYPE_LIST)) 54 55 static void capture_parse_pos(void *scanner, struct scan_context *scan_ctx, 56 config_setting_t *setting) 57 { 58 setting->line = (unsigned int)libconfig_yyget_lineno(scanner); 59 setting->file = libconfig_scanctx_current_filename(scan_ctx); 60 } 61 62 #define CAPTURE_PARSE_POS(S) \ 63 capture_parse_pos(scanner, scan_ctx, (S)) 64 65 void libconfig_yyerror(void *scanner, struct parse_context *ctx, 66 struct scan_context *scan_ctx, char const *s) 67 { 68 if(ctx->config->error_text) return; 69 ctx->config->error_line = libconfig_yyget_lineno(scanner); 70 ctx->config->error_text = s; 71 } 72 73 %} 74 75 %union 76 { 77 int ival; 78 long long llval; 79 double fval; 80 char *sval; 81 } 82 83 %token <ival> TOK_BOOLEAN TOK_INTEGER TOK_HEX 84 %token <llval> TOK_INTEGER64 TOK_HEX64 85 %token <fval> TOK_FLOAT 86 %token <sval> TOK_STRING TOK_NAME 87 %token TOK_EQUALS TOK_NEWLINE TOK_ARRAY_START TOK_ARRAY_END TOK_LIST_START TOK_LIST_END TOK_COMMA TOK_GROUP_START TOK_GROUP_END TOK_SEMICOLON TOK_GARBAGE TOK_ERROR 88 %destructor { free($$); } TOK_STRING 89 90 %% 91 92 configuration: 93 /* empty */ 94 | setting_list 95 ; 96 97 setting_list: 98 setting 99 | setting_list setting 100 ; 101 102 setting_list_optional: 103 /* empty */ 104 | setting_list 105 ; 106 107 setting_terminator: 108 /* empty */ 109 | TOK_SEMICOLON 110 | TOK_COMMA 111 ; 112 113 setting: 114 TOK_NAME 115 { 116 ctx->setting = config_setting_add(ctx->parent, $1, CONFIG_TYPE_NONE); 117 118 if(ctx->setting == NULL) 119 { 120 libconfig_yyerror(scanner, ctx, scan_ctx, err_duplicate_setting); 121 YYABORT; 122 } 123 else 124 { 125 CAPTURE_PARSE_POS(ctx->setting); 126 } 127 } 128 129 TOK_EQUALS value setting_terminator 130 ; 131 132 array: 133 TOK_ARRAY_START 134 { 135 if(IN_LIST()) 136 { 137 ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_ARRAY); 138 CAPTURE_PARSE_POS(ctx->parent); 139 } 140 else 141 { 142 ctx->setting->type = CONFIG_TYPE_ARRAY; 143 ctx->parent = ctx->setting; 144 ctx->setting = NULL; 145 } 146 } 147 simple_value_list_optional 148 TOK_ARRAY_END 149 { 150 if(ctx->parent) 151 ctx->parent = ctx->parent->parent; 152 } 153 ; 154 155 list: 156 TOK_LIST_START 157 { 158 if(IN_LIST()) 159 { 160 ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_LIST); 161 CAPTURE_PARSE_POS(ctx->parent); 162 } 163 else 164 { 165 ctx->setting->type = CONFIG_TYPE_LIST; 166 ctx->parent = ctx->setting; 167 ctx->setting = NULL; 168 } 169 } 170 value_list_optional 171 TOK_LIST_END 172 { 173 if(ctx->parent) 174 ctx->parent = ctx->parent->parent; 175 } 176 ; 177 178 value: 179 simple_value 180 | array 181 | list 182 | group 183 ; 184 185 string: 186 TOK_STRING { libconfig_parsectx_append_string(ctx, $1); free($1); } 187 | string TOK_STRING { libconfig_parsectx_append_string(ctx, $2); free($2); } 188 ; 189 190 simple_value: 191 TOK_BOOLEAN 192 { 193 if(IN_ARRAY() || IN_LIST()) 194 { 195 config_setting_t *e = config_setting_set_bool_elem(ctx->parent, -1, 196 (int)$1); 197 198 if(! e) 199 { 200 libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); 201 YYABORT; 202 } 203 else 204 { 205 CAPTURE_PARSE_POS(e); 206 } 207 } 208 else 209 config_setting_set_bool(ctx->setting, (int)$1); 210 } 211 | TOK_INTEGER 212 { 213 if(IN_ARRAY() || IN_LIST()) 214 { 215 config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, $1); 216 if(! e) 217 { 218 libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); 219 YYABORT; 220 } 221 else 222 { 223 config_setting_set_format(e, CONFIG_FORMAT_DEFAULT); 224 CAPTURE_PARSE_POS(e); 225 } 226 } 227 else 228 { 229 config_setting_set_int(ctx->setting, $1); 230 config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT); 231 } 232 } 233 | TOK_INTEGER64 234 { 235 if(IN_ARRAY() || IN_LIST()) 236 { 237 config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, $1); 238 if(! e) 239 { 240 libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); 241 YYABORT; 242 } 243 else 244 { 245 config_setting_set_format(e, CONFIG_FORMAT_DEFAULT); 246 CAPTURE_PARSE_POS(e); 247 } 248 } 249 else 250 { 251 config_setting_set_int64(ctx->setting, $1); 252 config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT); 253 } 254 } 255 | TOK_HEX 256 { 257 if(IN_ARRAY() || IN_LIST()) 258 { 259 config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, $1); 260 if(! e) 261 { 262 libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); 263 YYABORT; 264 } 265 else 266 { 267 config_setting_set_format(e, CONFIG_FORMAT_HEX); 268 CAPTURE_PARSE_POS(e); 269 } 270 } 271 else 272 { 273 config_setting_set_int(ctx->setting, $1); 274 config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX); 275 } 276 } 277 | TOK_HEX64 278 { 279 if(IN_ARRAY() || IN_LIST()) 280 { 281 config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, $1); 282 if(! e) 283 { 284 libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); 285 YYABORT; 286 } 287 else 288 { 289 config_setting_set_format(e, CONFIG_FORMAT_HEX); 290 CAPTURE_PARSE_POS(e); 291 } 292 } 293 else 294 { 295 config_setting_set_int64(ctx->setting, $1); 296 config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX); 297 } 298 } 299 | TOK_FLOAT 300 { 301 if(IN_ARRAY() || IN_LIST()) 302 { 303 config_setting_t *e = config_setting_set_float_elem(ctx->parent, -1, $1); 304 if(! e) 305 { 306 libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); 307 YYABORT; 308 } 309 else 310 { 311 CAPTURE_PARSE_POS(e); 312 } 313 } 314 else 315 config_setting_set_float(ctx->setting, $1); 316 } 317 | string 318 { 319 if(IN_ARRAY() || IN_LIST()) 320 { 321 const char *s = libconfig_parsectx_take_string(ctx); 322 config_setting_t *e = config_setting_set_string_elem(ctx->parent, -1, s); 323 __delete(s); 324 325 if(! e) 326 { 327 libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); 328 YYABORT; 329 } 330 else 331 { 332 CAPTURE_PARSE_POS(e); 333 } 334 } 335 else 336 { 337 const char *s = libconfig_parsectx_take_string(ctx); 338 config_setting_set_string(ctx->setting, s); 339 __delete(s); 340 } 341 } 342 ; 343 344 value_list: 345 value 346 | value_list TOK_COMMA value 347 | value_list TOK_COMMA 348 ; 349 350 value_list_optional: 351 /* empty */ 352 | value_list 353 ; 354 355 simple_value_list: 356 simple_value 357 | simple_value_list TOK_COMMA simple_value 358 | simple_value_list TOK_COMMA 359 ; 360 361 simple_value_list_optional: 362 /* empty */ 363 | simple_value_list 364 ; 365 366 group: 367 TOK_GROUP_START 368 { 369 if(IN_LIST()) 370 { 371 ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_GROUP); 372 CAPTURE_PARSE_POS(ctx->parent); 373 } 374 else 375 { 376 ctx->setting->type = CONFIG_TYPE_GROUP; 377 ctx->parent = ctx->setting; 378 ctx->setting = NULL; 379 } 380 } 381 setting_list_optional 382 TOK_GROUP_END 383 { 384 if(ctx->parent) 385 ctx->parent = ctx->parent->parent; 386 } 387 ; 388 389 %% 390