| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 | %{/* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */#include <ctype.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include "lkc.h"#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)#define PRINTD		0x0001#define DEBUG_PARSE	0x0002int cdebug = PRINTD;int yylex(void);static void yyerror(const char *err);static void zconfprint(const char *err, ...);static void zconf_error(const char *err, ...);static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);struct symbol *symbol_hash[SYMBOL_HASHSIZE];static struct menu *current_menu, *current_entry;%}%expect 32%union{	char *string;	struct file *file;	struct symbol *symbol;	struct expr *expr;	struct menu *menu;	const struct kconf_id *id;}%token <id>T_MAINMENU%token <id>T_MENU%token <id>T_ENDMENU%token <id>T_SOURCE%token <id>T_CHOICE%token <id>T_ENDCHOICE%token <id>T_COMMENT%token <id>T_CONFIG%token <id>T_MENUCONFIG%token <id>T_HELP%token <string> T_HELPTEXT%token <id>T_IF%token <id>T_ENDIF%token <id>T_DEPENDS%token <id>T_OPTIONAL%token <id>T_PROMPT%token <id>T_TYPE%token <id>T_DEFAULT%token <id>T_SELECT%token <id>T_IMPLY%token <id>T_RANGE%token <id>T_VISIBLE%token <id>T_OPTION%token <id>T_ON%token <string> T_WORD%token <string> T_WORD_QUOTE%token T_UNEQUAL%token T_LESS%token T_LESS_EQUAL%token T_GREATER%token T_GREATER_EQUAL%token T_CLOSE_PAREN%token T_OPEN_PAREN%token T_EOL%left T_OR%left T_AND%left T_EQUAL T_UNEQUAL%left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL%nonassoc T_NOT%type <string> prompt%type <symbol> nonconst_symbol%type <symbol> symbol%type <expr> expr%type <expr> if_expr%type <id> end%type <id> option_name%type <menu> if_entry menu_entry choice_entry%type <string> symbol_option_arg word_opt%destructor {	fprintf(stderr, "%s:%d: missing end statement for this entry\n",		$$->file->name, $$->lineno);	if (current_menu == $$)		menu_end_menu();} if_entry menu_entry choice_entry%{/* Include kconf_id.c here so it can see the token constants. */#include "kconf_id.c"%}%%input: nl start | start;start: mainmenu_stmt stmt_list | no_mainmenu_stmt stmt_list;/* mainmenu entry */mainmenu_stmt: T_MAINMENU prompt nl{	menu_add_prompt(P_MENU, $2, NULL);};/* Default main menu, if there's no mainmenu entry */no_mainmenu_stmt: /* empty */{	/*	 * Hack: Keep the main menu title on the heap so we can safely free it	 * later regardless of whether it comes from the 'prompt' in	 * mainmenu_stmt or here	 */	menu_add_prompt(P_MENU, xstrdup("Buildroot Configuration"), NULL);};stmt_list:	  /* empty */	| stmt_list common_stmt	| stmt_list choice_stmt	| stmt_list menu_stmt	| stmt_list end			{ zconf_error("unexpected end statement"); }	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }	| stmt_list option_name error T_EOL{	zconf_error("unexpected option \"%s\"", $2->name);}	| stmt_list error T_EOL		{ zconf_error("invalid statement"); };option_name:	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_IMPLY | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE;common_stmt:	  T_EOL	| if_stmt	| comment_stmt	| config_stmt	| menuconfig_stmt	| source_stmt;option_error:	  T_WORD error T_EOL		{ zconf_error("unknown option \"%s\"", $1); }	| error T_EOL			{ zconf_error("invalid option"); };/* config/menuconfig entry */config_entry_start: T_CONFIG nonconst_symbol T_EOL{	$2->flags |= SYMBOL_OPTIONAL;	menu_add_entry($2);	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name);};config_stmt: config_entry_start config_option_list{	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());};menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL{	$2->flags |= SYMBOL_OPTIONAL;	menu_add_entry($2);	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name);};menuconfig_stmt: menuconfig_entry_start config_option_list{	if (current_entry->prompt)		current_entry->prompt->type = P_MENU;	else		zconfprint("warning: menuconfig statement without prompt");	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());};config_option_list:	  /* empty */	| config_option_list config_option	| config_option_list symbol_option	| config_option_list depends	| config_option_list help	| config_option_list option_error	| config_option_list T_EOL;config_option: T_TYPE prompt_stmt_opt T_EOL{	menu_set_type($1->stype);	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",		zconf_curname(), zconf_lineno(),		$1->stype);};config_option: T_PROMPT prompt if_expr T_EOL{	menu_add_prompt(P_PROMPT, $2, $3);	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());};config_option: T_DEFAULT expr if_expr T_EOL{	menu_add_expr(P_DEFAULT, $2, $3);	if ($1->stype != S_UNKNOWN)		menu_set_type($1->stype);	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",		zconf_curname(), zconf_lineno(),		$1->stype);};config_option: T_SELECT nonconst_symbol if_expr T_EOL{	menu_add_symbol(P_SELECT, $2, $3);	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());};config_option: T_IMPLY nonconst_symbol if_expr T_EOL{	menu_add_symbol(P_IMPLY, $2, $3);	printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());};config_option: T_RANGE symbol symbol if_expr T_EOL{	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());};symbol_option: T_OPTION symbol_option_list T_EOL;symbol_option_list:	  /* empty */	| symbol_option_list T_WORD symbol_option_arg{	const struct kconf_id *id = kconf_id_lookup($2, strlen($2));	if (id && id->flags & TF_OPTION) {		menu_add_option(id->token, $3);		free($3);	}	else		zconfprint("warning: ignoring unknown option %s", $2);	free($2);};symbol_option_arg:	  /* empty */		{ $$ = NULL; }	| T_EQUAL prompt	{ $$ = $2; };/* choice entry */choice: T_CHOICE word_opt T_EOL{	struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);	sym->flags |= SYMBOL_AUTO;	menu_add_entry(sym);	menu_add_expr(P_CHOICE, NULL, NULL);	free($2);	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());};choice_entry: choice choice_option_list{	$$ = menu_add_menu();};choice_end: end{	if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {		menu_end_menu();		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());	}};choice_stmt: choice_entry choice_block choice_end;choice_option_list:	  /* empty */	| choice_option_list choice_option	| choice_option_list depends	| choice_option_list help	| choice_option_list T_EOL	| choice_option_list option_error;choice_option: T_PROMPT prompt if_expr T_EOL{	menu_add_prompt(P_PROMPT, $2, $3);	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());};choice_option: T_TYPE prompt_stmt_opt T_EOL{	if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {		menu_set_type($1->stype);		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",			zconf_curname(), zconf_lineno(),			$1->stype);	} else		YYERROR;};choice_option: T_OPTIONAL T_EOL{	current_entry->sym->flags |= SYMBOL_OPTIONAL;	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());};choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL{	if ($1->stype == S_UNKNOWN) {		menu_add_symbol(P_DEFAULT, $2, $3);		printd(DEBUG_PARSE, "%s:%d:default\n",			zconf_curname(), zconf_lineno());	} else		YYERROR;};choice_block:	  /* empty */	| choice_block common_stmt;/* if entry */if_entry: T_IF expr nl{	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());	menu_add_entry(NULL);	menu_add_dep($2);	$$ = menu_add_menu();};if_end: end{	if (zconf_endtoken($1, T_IF, T_ENDIF)) {		menu_end_menu();		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());	}};if_stmt: if_entry if_block if_end;if_block:	  /* empty */	| if_block common_stmt	| if_block menu_stmt	| if_block choice_stmt;/* menu entry */menu: T_MENU prompt T_EOL{	menu_add_entry(NULL);	menu_add_prompt(P_MENU, $2, NULL);	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());};menu_entry: menu visibility_list depends_list{	$$ = menu_add_menu();};menu_end: end{	if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {		menu_end_menu();		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());	}};menu_stmt: menu_entry menu_block menu_end;menu_block:	  /* empty */	| menu_block common_stmt	| menu_block menu_stmt	| menu_block choice_stmt;source_stmt: T_SOURCE prompt T_EOL{	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);	zconf_nextfile($2);	free($2);};/* comment entry */comment: T_COMMENT prompt T_EOL{	menu_add_entry(NULL);	menu_add_prompt(P_COMMENT, $2, NULL);	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());};comment_stmt: comment depends_list;/* help option */help_start: T_HELP T_EOL{	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());	zconf_starthelp();};help: help_start T_HELPTEXT{	if (current_entry->help) {		free(current_entry->help);		zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used",			   current_entry->sym->name ?: "<choice>");	}	/* Is the help text empty or all whitespace? */	if ($2[strspn($2, " \f\n\r\t\v")] == '\0')		zconfprint("warning: '%s' defined with blank help text",			   current_entry->sym->name ?: "<choice>");	current_entry->help = $2;};/* depends option */depends_list:	  /* empty */	| depends_list depends	| depends_list T_EOL	| depends_list option_error;depends: T_DEPENDS T_ON expr T_EOL{	menu_add_dep($3);	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());};/* visibility option */visibility_list:	  /* empty */	| visibility_list visible	| visibility_list T_EOL;visible: T_VISIBLE if_expr{	menu_add_visibility($2);};/* prompt statement */prompt_stmt_opt:	  /* empty */	| prompt if_expr{	menu_add_prompt(P_PROMPT, $1, $2);};prompt:	  T_WORD	| T_WORD_QUOTE;end:	  T_ENDMENU T_EOL	{ $$ = $1; }	| T_ENDCHOICE T_EOL	{ $$ = $1; }	| T_ENDIF T_EOL		{ $$ = $1; };nl:	  T_EOL	| nl T_EOL;if_expr:  /* empty */			{ $$ = NULL; }	| T_IF expr			{ $$ = $2; };expr:	  symbol				{ $$ = expr_alloc_symbol($1); }	| symbol T_LESS symbol			{ $$ = expr_alloc_comp(E_LTH, $1, $3); }	| symbol T_LESS_EQUAL symbol		{ $$ = expr_alloc_comp(E_LEQ, $1, $3); }	| symbol T_GREATER symbol		{ $$ = expr_alloc_comp(E_GTH, $1, $3); }	| symbol T_GREATER_EQUAL symbol		{ $$ = expr_alloc_comp(E_GEQ, $1, $3); }	| symbol T_EQUAL symbol			{ $$ = expr_alloc_comp(E_EQUAL, $1, $3); }	| symbol T_UNEQUAL symbol		{ $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }	| T_OPEN_PAREN expr T_CLOSE_PAREN	{ $$ = $2; }	| T_NOT expr				{ $$ = expr_alloc_one(E_NOT, $2); }	| expr T_OR expr			{ $$ = expr_alloc_two(E_OR, $1, $3); }	| expr T_AND expr			{ $$ = expr_alloc_two(E_AND, $1, $3); };/* For symbol definitions, selects, etc., where quotes are not accepted */nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); };symbol:	  nonconst_symbol	| T_WORD_QUOTE	{ $$ = sym_lookup($1, SYMBOL_CONST); free($1); };word_opt: /* empty */			{ $$ = NULL; }	| T_WORD%%void conf_parse(const char *name){	const char *tmp;	struct symbol *sym;	int i;	zconf_initscan(name);	sym_init();	_menu_init();	if (getenv("ZCONF_DEBUG"))		yydebug = 1;	yyparse();	if (yynerrs)		exit(1);	if (!modules_sym)		modules_sym = sym_find( "n" );	tmp = rootmenu.prompt->text;	rootmenu.prompt->text = _(rootmenu.prompt->text);	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);	free((char*)tmp);	menu_finalize(&rootmenu);	for_all_symbols(i, sym) {		if (sym_check_deps(sym))			yynerrs++;	}	if (yynerrs)		exit(1);	sym_set_change_count(1);}static const char *zconf_tokenname(int token){	switch (token) {	case T_MENU:		return "menu";	case T_ENDMENU:		return "endmenu";	case T_CHOICE:		return "choice";	case T_ENDCHOICE:	return "endchoice";	case T_IF:		return "if";	case T_ENDIF:		return "endif";	case T_DEPENDS:		return "depends";	case T_VISIBLE:		return "visible";	}	return "<token>";}static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken){	if (id->token != endtoken) {		zconf_error("unexpected '%s' within %s block",			id->name, zconf_tokenname(starttoken));		yynerrs++;		return false;	}	if (current_menu->file != current_file) {		zconf_error("'%s' in different file than '%s'",			id->name, zconf_tokenname(starttoken));		fprintf(stderr, "%s:%d: location of the '%s'\n",			current_menu->file->name, current_menu->lineno,			zconf_tokenname(starttoken));		yynerrs++;		return false;	}	return true;}static void zconfprint(const char *err, ...){	va_list ap;	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());	va_start(ap, err);	vfprintf(stderr, err, ap);	va_end(ap);	fprintf(stderr, "\n");}static void zconf_error(const char *err, ...){	va_list ap;	yynerrs++;	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());	va_start(ap, err);	vfprintf(stderr, err, ap);	va_end(ap);	fprintf(stderr, "\n");}static void yyerror(const char *err){	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);}static void print_quoted_string(FILE *out, const char *str){	const char *p;	int len;	putc('"', out);	while ((p = strchr(str, '"'))) {		len = p - str;		if (len)			fprintf(out, "%.*s", len, str);		fputs("\\\"", out);		str = p + 1;	}	fputs(str, out);	putc('"', out);}static void print_symbol(FILE *out, struct menu *menu){	struct symbol *sym = menu->sym;	struct property *prop;	if (sym_is_choice(sym))		fprintf(out, "\nchoice\n");	else		fprintf(out, "\nconfig %s\n", sym->name);	switch (sym->type) {	case S_BOOLEAN:		fputs("  bool\n", out);		break;	case S_TRISTATE:		fputs("  tristate\n", out);		break;	case S_STRING:		fputs("  string\n", out);		break;	case S_INT:		fputs("  integer\n", out);		break;	case S_HEX:		fputs("  hex\n", out);		break;	default:		fputs("  ???\n", out);		break;	}	for (prop = sym->prop; prop; prop = prop->next) {		if (prop->menu != menu)			continue;		switch (prop->type) {		case P_PROMPT:			fputs("  prompt ", out);			print_quoted_string(out, prop->text);			if (!expr_is_yes(prop->visible.expr)) {				fputs(" if ", out);				expr_fprint(prop->visible.expr, out);			}			fputc('\n', out);			break;		case P_DEFAULT:			fputs( "  default ", out);			expr_fprint(prop->expr, out);			if (!expr_is_yes(prop->visible.expr)) {				fputs(" if ", out);				expr_fprint(prop->visible.expr, out);			}			fputc('\n', out);			break;		case P_CHOICE:			fputs("  #choice value\n", out);			break;		case P_SELECT:			fputs( "  select ", out);			expr_fprint(prop->expr, out);			fputc('\n', out);			break;		case P_IMPLY:			fputs( "  imply ", out);			expr_fprint(prop->expr, out);			fputc('\n', out);			break;		case P_RANGE:			fputs( "  range ", out);			expr_fprint(prop->expr, out);			fputc('\n', out);			break;		case P_MENU:			fputs( "  menu ", out);			print_quoted_string(out, prop->text);			fputc('\n', out);			break;		default:			fprintf(out, "  unknown prop %d!\n", prop->type);			break;		}	}	if (menu->help) {		int len = strlen(menu->help);		while (menu->help[--len] == '\n')			menu->help[len] = 0;		fprintf(out, "  help\n%s\n", menu->help);	}}void zconfdump(FILE *out){	struct property *prop;	struct symbol *sym;	struct menu *menu;	menu = rootmenu.list;	while (menu) {		if ((sym = menu->sym))			print_symbol(out, menu);		else if ((prop = menu->prompt)) {			switch (prop->type) {			case P_COMMENT:				fputs("\ncomment ", out);				print_quoted_string(out, prop->text);				fputs("\n", out);				break;			case P_MENU:				fputs("\nmenu ", out);				print_quoted_string(out, prop->text);				fputs("\n", out);				break;			default:				;			}			if (!expr_is_yes(prop->visible.expr)) {				fputs("  depends ", out);				expr_fprint(prop->visible.expr, out);				fputc('\n', out);			}		}		if (menu->list)			menu = menu->list;		else if (menu->next)			menu = menu->next;		else while ((menu = menu->parent)) {			if (menu->prompt && menu->prompt->type == P_MENU)				fputs("\nendmenu\n", out);			if (menu->next) {				menu = menu->next;				break;			}		}	}}#include "zconf.lex.c"#include "util.c"#include "confdata.c"#include "expr.c"#include "symbol.c"#include "menu.c"
 |