%define api.pure %glr-parser %skeleton "glr.c" %locations %debug %error-verbose %code requires { #include "theme.h" } %{ #include #include #include "theme.h" #include "lexer/theme-parser.h" Widget *rofi_theme = NULL; void yyerror(YYLTYPE *yylloc, const char* s); int yylex (YYSTYPE *, YYLTYPE *); %} %union { int ival; double fval; char *sval; int bval; ThemeColor colorval; Widget *theme; GList *name_path; Property *property; GHashTable *property_list; } %token T_INT %token T_DOUBLE %token T_STRING %token N_STRING %token T_BOOLEAN %token T_COLOR %token CLASS_NAME %token BOPEN "bracket open"; %token BCLOSE "bracket close"; %token PSEP "property separator"; %token PCLOSE "property close"; %token NSEP "Name separator"; %token CLASS_PREFIX "Class prefix"; %token NAME_PREFIX "Name prefix"; %type entry %type pvalue %type entries %type start %type name_path %type state_path %type property %type property_list %type optional_properties %start start %% start: optional_properties entries { $$ = $2; if ( $1 != NULL ) { $$->properties = $1; } } ; entries: %empty { // There is always a base widget. $$ = rofi_theme = (Widget*)g_malloc0 (sizeof(Widget)); rofi_theme->name = g_strdup ( "Window" ); } | entries entry { $$ = $1; } ; entry: CLASS_NAME state_path BOPEN optional_properties BCLOSE { Widget *widget = rofi_theme_find_or_create_class ( rofi_theme , $1 ); for ( GList *iter = g_list_first ( $2 ); iter ; iter = g_list_next ( iter ) ) { widget = rofi_theme_find_or_create_class ( widget, iter->data ); } g_list_foreach ( $2, (GFunc)g_free , NULL ); g_list_free ( $2 ); if ( widget->properties != NULL ) { fprintf(stderr, "Properties already set on this widget.\n"); exit ( EXIT_FAILURE ); } widget->properties = $4; } | NAME_PREFIX name_path state_path BOPEN optional_properties BCLOSE { Widget *widget = rofi_theme; for ( GList *iter = g_list_first ( $2 ); iter ; iter = g_list_next ( iter ) ) { widget = rofi_theme_find_or_create_class ( widget, iter->data ); } g_list_foreach ( $2, (GFunc)g_free , NULL ); g_list_free ( $2 ); for ( GList *iter = g_list_first ( $3 ); iter ; iter = g_list_next ( iter ) ) { widget = rofi_theme_find_or_create_class ( widget, iter->data ); } g_list_foreach ( $3, (GFunc)g_free , NULL ); g_list_free ( $3 ); if ( widget->properties != NULL ) { fprintf(stderr, "Properties already set on this widget.\n"); exit ( EXIT_FAILURE ); } widget->properties = $5; }; /** * properties */ optional_properties : %empty { $$ = NULL; } | property_list { $$ = $1; } ; property_list: property { $$ = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, (GDestroyNotify)rofi_theme_property_free ); g_hash_table_replace ( $$, $1->name, $1 ); } | property_list property { // Old will be free'ed, and key/value will be replaced. g_hash_table_replace ( $$, $2->name, $2 ); } ; property : pvalue PSEP T_INT PCLOSE { $$ = rofi_theme_property_create ( P_INTEGER ); $$->name = $1; $$->value.i = $3; } | pvalue PSEP T_DOUBLE PCLOSE { $$ = rofi_theme_property_create ( P_DOUBLE ); $$->name = $1; $$->value.f = $3; } | pvalue PSEP T_COLOR PCLOSE { $$ = rofi_theme_property_create ( P_COLOR ); $$->name = $1; $$->value.color = $3; } | pvalue PSEP T_STRING PCLOSE { $$ = rofi_theme_property_create ( P_STRING ); $$->name = $1; $$->value.s = $3; } | pvalue PSEP T_BOOLEAN PCLOSE { $$ = rofi_theme_property_create ( P_BOOLEAN ); $$->name = $1; $$->value.b = $3; } ; pvalue: N_STRING { $$ = $1; } name_path: %empty { $$ = NULL; } | N_STRING { $$ = g_list_append ( NULL, $1 );} | name_path NSEP N_STRING { $$ = g_list_append ( $1, $3);} ; state_path: %empty { $$ = NULL; } | N_STRING { $$ = g_list_append ( NULL, $1 );} | state_path NSEP N_STRING { $$ = g_list_append ( $1, $3);} ; %%