Messages in this thread | | | Date | Sat, 10 Aug 2002 15:36:17 +0100 | From | Christoph Hellwig <> | Subject | Re: [patch 2/12] eyestrain relief |
| |
On Sat, Aug 10, 2002 at 04:36:08PM +0200, Sam Ravnborg wrote: > On Sat, Aug 10, 2002 at 12:14:30PM +0100, Christoph Hellwig wrote: > > > > *hint* *hint* mconfig doesn't let your eyes burn.. > > > > ftp://ftp.kernel.org/pub/linux/kernel/people/hch/mconfig/ > > Any plans to share parser.y with the rest of the world? > It is missing in the tar-ball.
It's below. Bonus points go to the one who submits the automake magic to generated parser.tab.{c,h} on the fly.
/* * parser.y * * Copyright 1998, 1999 Michael Elizabeth Chastain, <mailto:mec@shout.net>. * Licensed under the Gnu Public License, Version 2. * * Parse the language defined in Documentation/kbuild/config-language.txt * in the Linux kernel source. * * Also parses the little language of defconfig and .config files. */
/* * Global parser state variables. */
%{ #include <string.h>
#include "mconfig.h"
int parser_magic_cookie; block_type * parser_block_top; def_line_list_type * parser_def_line_list; int parser_error_count; int parser_warning_count; %}
/* * Union of all parser node types across all languages. */
%union { struct void_tag * value_void; const char * value_input_point;
lexeme_type value_lexeme; atom_type * value_atom; atom_list_type * value_atom_list; word_type * value_word; word_list_type * value_word_list; prompt_type * value_prompt; symbol_type * value_symbol; choice_list_type * value_choice_list; unset_list_type * value_unset_list;
expr_type * value_expr;
statement_type * value_statement; block_type * value_block;
def_line_type * value_def_line; def_line_list_type * value_def_line_list; }
/* * Grammar symbols to handle language type. */
%type <value_void> start %type <value_void> init %type <value_void> start_language
%token <value_void> COOKIE_CONFIG_LANGUAGE %token <value_void> COOKIE_DEF_CONFIG %token <value_void> COOKIE_HELP_TEXT
/* * Grammar symbols for Config Language. */
%type <value_block> block %type <value_block> scoped_block
%token <value_input_point> SOURCE
%type <value_statement> statement
%token <value_input_point> MAINMENU_OPTION %token <value_input_point> ENDMENU
%token <value_input_point> MAINMENU_NAME %token <value_input_point> COMMENT %token <value_input_point> TEXT
%token <value_input_point> UNSET
%token <value_input_point> ASK_BOOL %token <value_input_point> ASK_HEX %token <value_input_point> ASK_INT %token <value_input_point> ASK_STRING %token <value_input_point> ASK_TRISTATE
%token <value_input_point> DEF_BOOL %token <value_input_point> DEF_HEX %token <value_input_point> DEF_INT %token <value_input_point> DEF_STRING %token <value_input_point> DEF_TRISTATE
%token <value_input_point> DEP_BOOL %token <value_input_point> DEP_MBOOL %token <value_input_point> DEP_HEX %token <value_input_point> DEP_INT %token <value_input_point> DEP_STRING %token <value_input_point> DEP_TRISTATE
%token <value_input_point> CHOICE %token <value_input_point> NCHOICE
%token <value_input_point> IF %token <value_void> THEN %token <value_void> ELSE %token <value_void> FI %token <value_void> '[' %token <value_void> ']' %token <value_void> ';' %type <value_void> semi_or_nl
%type <value_expr> expr %type <value_expr> expr_not %type <value_expr> expr_and %type <value_expr> expr_or %type <value_expr> expr_predicate %type <value_expr> expr_word %token <value_input_point> '!' %token <value_input_point> '=' %token <value_void> DASH_O %token <value_void> DASH_A
%type <value_choice_list> choice_list %type <value_unset_list> unset_list %type <value_prompt> prompt %type <value_symbol> symbol
%type <value_word_list> extra_word_list %type <value_word> word %type <value_word> word_dquote %type <value_atom_list> atom_list %type <value_atom> atom_literal %type <value_atom> atom_variable %token <value_input_point> '"' %token <value_input_point> '$' %token <value_lexeme> LEXEME
/* * Grammar symbols for defconfig files. */
%token <value_lexeme> ISNOTSET %type <value_def_line> def_line %type <value_def_line_list> def_line_list
/* * Grammar symbols for help text. */
%%
/* * The start symbol. * * This is a kludge. The lexer gives me a cookie to indicate language type: * * arch/$ARCH/Config.in, ordinary Config Language * .config or defconfig file * help text (?) * * I need this kludge for two reasons. First, bison gets unhappy if I use * multiple parsers, because the lexer needs to see a single set of token * constants and single YYLVAL type. Second, I like to re-use some of the * low-level constructs such as atoms, and separate parsers won't let me do * that. */
start: init start_language { }
/* * This symbol initializes the return state for each parse. */
init: { parser_block_top = NULL; parser_def_line_list = NULL; parser_error_count = 0; parser_warning_count = 0; }
/* * Start symbol for Config Language. * Wrap the top-level block in a menu if it isn't already one. * Reducing to this symbol copies the top block pointer to a global place. */
start_language: COOKIE_HELP_TEXT block { /* prompt->value.ptr = "Mconfig Help Menu"; prompt->value.len = 17; */ parser_block_top = $2; }
start_language: COOKIE_CONFIG_LANGUAGE block { if ( $2->first != NULL && $2->first->next == NULL && $2->first->verb == verb_MENU ) { parser_block_top = $2; } else { prompt_type * prompt; statement_type * statement;
prompt = grab_memory( sizeof(*prompt) ); prompt->next = NULL; prompt->value.ptr = "Main Menu"; prompt->value.len = 9;
statement = grab_memory( sizeof(*statement) ); statement->next = NULL; statement->verb = verb_MENU; statement->sc_title = prompt; statement->sc_condition = NULL; statement->sc_block_left = $2; statement->sc_block_right = NULL;
parser_block_top = grab_memory( sizeof(*parser_block_top) ); parser_block_top->first = statement; parser_block_top->last = statement; } }
/* * A block is a list of statements. */
block: scoped_block { $$ = $1; /* scope_close( ); */ }
scoped_block: { $$ = grab_memory( sizeof(*$$) ); $$->first = NULL; $$->last = NULL; /* scope_open( ); */ }
scoped_block: scoped_block statement { $$ = $1;
if ( $$->first == NULL ) $$->first = $2; if ( $$->last != NULL ) $$->last->next = $2; $$->last = $2; }
scoped_block: scoped_block '\n' { $$ = $1; }
/* * The source command is special: it gets executed immediately. */
scoped_block: scoped_block SOURCE LEXEME '\n' { char * name; const char * error_string;
$$ = $1;
name = grab_memory( strlen(argument.ds) + $3.piece.len + 1 ); sprintf( name, "%s%.*s", argument.ds, $3.piece.len, $3.piece.ptr );
if ( input_push_file( name, &error_string ) < 0 ) { parser_error( error_string, $2 ); YYABORT; } }
/* * Menu block. */
statement: MAINMENU_OPTION word '\n' block ENDMENU '\n' { if ( $2->literal.len < 0 ) parser_error( "mainmenu_option argument must be literal", $1 );
if ( $2->literal.len != 12 || memcmp( $2->literal.ptr, "next_comment", 12 ) != 0 ) parser_error( "mainmenu_option unknown argument %.*s", $1, $2->literal.len, $2->literal.ptr );
if ( $4->first == NULL || $4->first->verb != verb_comment ) parser_error( "mainmenu_option next_comment must be followed by comment", $1 );
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_MENU; $$->sc_title = ($4->first != NULL) ? $4->first->sb_prompt : NULL; $$->sc_condition = NULL; $$->sc_block_left = $4; $$->sc_block_right = NULL; }
/* * If statement. */
statement: IF '[' expr ']' semi_or_nl THEN block FI '\n' { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_IF; $$->sc_title = NULL; $$->sc_condition = $3; $$->sc_block_left = $7; $$->sc_block_right = NULL; }
statement: IF '[' expr ']' semi_or_nl THEN block ELSE block FI '\n' { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_IF; $$->sc_title = NULL; $$->sc_condition = $3; $$->sc_block_left = $7; $$->sc_block_right = $9;
/* * FIXME: take the intersection of definitions in $7 and $9 * and define those for this statement. */ }
semi_or_nl: ';' | '\n' { ; }
/* * Simple text-like statements. */
statement: MAINMENU_NAME prompt extra_word_list '\n' { if ( $3->first != NULL ) parser_warning( "mainmenu_name command has extra arguments", $1 );
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_mainmenu_name; $$->sb_prompt = $2; $$->sb_symbol = NULL; $$->sb_def_value = NULL; $$->sb_dep_list = NULL; }
statement: COMMENT prompt extra_word_list '\n' { if ( $3->first != NULL ) parser_warning( "comment command has extra arguments", $1 );
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_comment; $$->sb_prompt = $2; $$->sb_symbol = NULL; $$->sb_def_value = NULL; $$->sb_dep_list = NULL; }
statement: TEXT prompt extra_word_list '\n' { if ( $3->first != NULL ) parser_warning( "text command has extra arguments", $1 );
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_text; $$->sb_prompt = $2; $$->sb_symbol = NULL; $$->sb_def_value = NULL; $$->sb_dep_list = NULL; }
/* * The UNSET verb. This is a hack used in arch/{alpha,mips}/config.in. * I could actually start ignoring this once I fully implement TANDV/TAODAQ. */
statement: UNSET unset_list '\n' { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_unset; $$->su_unset_list = $2; }
/* * Command lines: ASK_*. */
statement: ASK_BOOL prompt symbol extra_word_list '\n' { #ifndef STRICT_TYPES if ( $4->first != NULL ) parser_warning( "bool command has extra arguments", $1 ); #endif
if ( $3->type == type_unset ) $3->type = type_bool; #ifdef STRICT_TYPES else if ( $3->type != type_bool ) #else else if ( $3->type != type_bool && $3->type != type_nchoice_slave ) #endif parser_error( "bool command re-defines a non-bool symbol %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_ask_bool; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = NULL; /* ignore extra arguments even without STRICT_SYNTAX */ $$->sb_dep_list = NULL; }
statement: ASK_HEX prompt symbol word extra_word_list '\n' { if ( $5->first != NULL ) parser_warning( "hex command has extra arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_hex; else if ( $3->type != type_hex ) parser_error( "hex command re-defines a non-hex symbol %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_ask_hex; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = $4; $$->sb_dep_list = NULL; }
statement: ASK_INT prompt symbol word extra_word_list '\n' { if ( $5->first != NULL ) parser_warning( "int command has extra arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_int; else if ( $3->type != type_int ) parser_error( "int command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_ask_int; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = $4; $$->sb_dep_list = NULL; }
/* * The string command has an optional default value. */
statement: ASK_STRING prompt symbol '\n' { word_type * word;
parser_warning( "string command needs a default value", $1 );
if ( $3->type == type_unset ) $3->type = type_string; else if ( $3->type != type_string ) parser_error( "string command redefines %.*s", $1, $3->name.len, $3->name.ptr);
word = grab_memory( sizeof(*word) ); word->next = NULL; word->dquote = 1; word->literal.ptr = ""; word->literal.len = 0; word->atom_first = NULL;
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_ask_string; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = word; $$->sb_dep_list = NULL; }
statement: ASK_STRING prompt symbol word extra_word_list '\n' { if ( $5->first != NULL ) parser_warning( "string command has extra arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_string; else if ( $3->type != type_string ) parser_error( "string command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_ask_string; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = $4; $$->sb_dep_list = NULL; }
statement: ASK_TRISTATE prompt symbol extra_word_list '\n' { #ifndef STRICT_TYPES if ( $4->first != NULL ) parser_warning( "tristate command has extra arguments", $1 ); #endif if ( $3->type == type_unset ) $3->type = type_tristate; #ifdef STRICT_TYPES else if ( $3->type != type_tristate ) #else else if ( $3->type != type_tristate && $3->type != type_bool ) #endif parser_error( "tristate command re-defines a non-tristate symbol %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_ask_tristate; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = NULL; /* ignore extra arguments even without STRICT_SYNTAX */ $$->sb_dep_list = NULL; }
/* * Command lines: DEF_*. */
statement: DEF_BOOL symbol word extra_word_list '\n' { if ( $4->first != NULL ) parser_warning( "define_bool command has extra arguments", $1 );
if ( $2->type == type_unset ) $2->type = type_bool; #ifdef STRICT_TYPES else if ( $2->type != type_bool ) #else else if ( $2->type != type_bool && $2->type != type_nchoice_slave && $2->type != type_tristate) #endif parser_error( "define_bool command re-defines a non-bool symbol %.*s", $1, $2->name.len, $2->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_def_bool; $$->sb_prompt = NULL; $$->sb_symbol = $2; $$->sb_def_value = $3; $$->sb_dep_list = NULL; }
statement: DEF_HEX symbol word extra_word_list '\n' { if ( $4->first != NULL ) parser_warning( "define_hex command has extra arguments", $1 );
if ( $2->type == type_unset ) $2->type = type_hex; else if ( $2->type != type_hex ) parser_error( "define_hex command redefines %.*s", $1, $2->name.len, $2->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_def_hex; $$->sb_prompt = NULL; $$->sb_symbol = $2; $$->sb_def_value = $3; $$->sb_dep_list = NULL; }
statement: DEF_INT symbol word extra_word_list '\n' { if ( $4->first != NULL ) parser_warning( "define_int command has extra arguments", $1 );
if ( $2->type == type_unset ) $2->type = type_int; else if ( $2->type != type_int ) parser_error( "define_int command redefines %.*s", $1, $2->name.len, $2->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_def_int; $$->sb_prompt = NULL; $$->sb_symbol = $2; $$->sb_def_value = $3; $$->sb_dep_list = NULL; }
statement: DEF_STRING symbol word extra_word_list '\n' { if ( $4->first != NULL ) parser_warning( "define_string command has extra arguments", $1 );
if ( $2->type == type_unset ) $2->type = type_string; else if ( $2->type != type_string ) parser_error( "define_string command redefines %.*s", $1, $2->name.len, $2->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_def_string; $$->sb_prompt = NULL; $$->sb_symbol = $2; $$->sb_def_value = $3; $$->sb_dep_list = NULL; }
statement: DEF_TRISTATE symbol word extra_word_list '\n' { if ( $4->first != NULL ) parser_warning( "define_tristate command has extra arguments", $1 );
if ( $2->type == type_unset ) $2->type = type_tristate; else if ( $2->type != type_tristate ) parser_error( "define_tristate command redefines %.*s", $1, $2->name.len, $2->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_def_tristate; $$->sb_prompt = NULL; $$->sb_symbol = $2; $$->sb_def_value = $3; $$->sb_dep_list = NULL; }
/* * Command lines: DEP_*. */
statement: DEP_BOOL prompt symbol extra_word_list '\n' { if ( $4->first == NULL ) parser_warning( "dep_bool command has no dependency arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_bool; #ifdef STRICT_TYPES else if ( $3->type != type_bool ) #else else if ( $3->type != type_bool && $3->type != type_nchoice_slave) #endif parser_error( "dep_bool command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_dep_bool; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = NULL; $$->sb_dep_list = $4; }
statement: DEP_MBOOL prompt symbol extra_word_list '\n' { if ( $4->first == NULL ) parser_warning( "dep_mbool command has no dependency arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_bool; #ifdef STRICT_TYPES else if ( $3->type != type_bool ) #else else if ( $3->type != type_bool && $3->type != type_nchoice_slave) #endif parser_error( "dep_mbool command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_dep_mbool; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = NULL; $$->sb_dep_list = $4; }
statement: DEP_HEX prompt symbol word extra_word_list '\n' { if ( $5->first == NULL ) parser_warning( "dep_hex command has no dependency arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_hex; else if ( $3->type != type_hex ) parser_error( "dep_hex command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_dep_hex; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = $4; $$->sb_dep_list = $5; }
statement: DEP_INT prompt symbol word extra_word_list '\n' { if ( $5->first == NULL ) parser_warning( "dep_int command has no dependency arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_int; else if ( $3->type != type_int ) parser_error( "dep_int command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_dep_int; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = $4; $$->sb_dep_list = $5; }
statement: DEP_STRING prompt symbol word extra_word_list '\n' { if ( $5->first == NULL ) parser_warning( "warning: dep_string command has no dependency arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_string; else if ( $3->type != type_string ) parser_error( "dep_string command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_dep_string; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = $4; $$->sb_dep_list = $5; }
statement: DEP_TRISTATE prompt symbol extra_word_list '\n' { if ( $4->first == NULL ) parser_warning( "dep_tristate command has no dependency arguments", $1 );
if ( $3->type == type_unset ) $3->type = type_tristate; else if ( $3->type != type_tristate ) parser_error( "dep_tristate command redefines %.*s", $1, $3->name.len, $3->name.ptr);
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_dep_tristate; $$->sb_prompt = $2; $$->sb_symbol = $3; $$->sb_def_value = NULL; $$->sb_dep_list = $4; }
/* * Choice list, classic style. * * Example (from 2.3.25-pre2 arch/arm/onfig.in): * * $1 choice * $2 'ARM system type' * $3 "Archimedes CONFIG_ARCH_ARC \ * A5000 CONFIG_ARCH_A5K \ * RiscPC CONFIG_ARCH_RPC \ * EBSA-110 CONFIG_ARCH_EBSA110 \ * Footbridge-based CONFIG_FOOTBRIDGE" * $4 RiscPC * * $2 goes into the statement node as is. * $3 gets parsed, by hand, into a ps-list. * $4 gets translated to a symbol while I am parsing $3. */
statement: CHOICE prompt word word extra_word_list '\n' { choice_list_type * choice_list; /* choice list for $3 */ char * choices; /* choice string from $3 */ char * cursor; /* scanner for choices */ int choice_count = 0; /* count of $3 */ int default_index = -1; /* index of $4 in $3 */ int match_exact = 0; /* match counter for $4 */ int match_partial = 0; /* match counter for $4 */
if ( $5->first != NULL ) parser_warning( "choice command has extra arguments", $1 );
if ( $4->literal.len < 0 ) parser_error( "choice command default value must be literal", $1 );
if ( $3->literal.len < 0 ) parser_error( "choice command choice-list must be literal", $1 );
/* * Build a new prompt-symbol list. */
choice_list = grab_memory( sizeof(*choice_list) ); choice_list->prompt_first = NULL; choice_list->prompt_last = NULL; choice_list->symbol_first = NULL; choice_list->symbol_last = NULL;
/* * I need a private copy of the choice string for three reasons: * (1) I need a null-terminated string, not a piece, for strtok * (2) strtok likes to scribble on its input * (3) I may not even *have* a piece (error case) */
if ( $3->literal.len < 0 ) { choices = grab_memory( 1 ); choices [0] = '\0'; } else { choices = grab_memory( $3->literal.len+1 ); memcpy( choices, $3->literal.ptr, $3->literal.len ); choices [$3->literal.len] = '\0'; }
/* * Scan off one pair at a time. */
for ( cursor = choices; ; cursor = NULL ) { const char * ptr; prompt_type * prompt; symbol_type * symbol;
/* * Grab the prompt. */
ptr = strtok( cursor, " \n\t\f\v" ); if ( ptr == NULL ) break;
prompt = grab_memory( sizeof(*prompt) ); prompt->next = NULL; prompt->value.ptr = ptr; prompt->value.len = strlen(ptr);
/* * Grab the symbol. */
ptr = strtok( NULL, " \n\t\f\v" ); if ( ptr == NULL ) { parser_error( "choice list must have an even number of words", $1 ); break; }
{ piece_type name; name.ptr = ptr; name.len = strlen(ptr); symbol = symbol_create( name ); /* scope_define( symbol ); */ }
/* * Choice symbols need to have unique definitions (imagine * someone doing define_bool on an unselected choice outside * the choice list!) */
if ( symbol->type == type_unset ) symbol->type = type_nchoice_slave; else parser_error( "choice command re-defines %.*s", $1, symbol->name.len, symbol->name.ptr);
/* * Append to choice_list. */
if ( choice_list->prompt_first == NULL ) choice_list->prompt_first = prompt; if ( choice_list->prompt_last != NULL ) choice_list->prompt_last->next = prompt; choice_list->prompt_last = prompt;
if ( choice_list->symbol_first == NULL ) choice_list->symbol_first = symbol; if ( choice_list->symbol_last != NULL ) choice_list->symbol_last->next = symbol; choice_list->symbol_last = symbol;
/* * Translate default from a value to a symbol name. * E.g., "RiscPC" -> CONFIG_ARCH_RPC * What a *stupid* syntax! */ if ( $4->literal.len >= 0 && $4->literal.len <= prompt->value.len && memcmp( $4->literal.ptr, prompt->value.ptr, $4->literal.len ) == 0 ) { if ( $4->literal.len == prompt->value.len ) { if ( match_exact++ == 0 ) default_index = choice_count; } else { if ( match_partial++ == 0 && match_exact == 0 ) default_index = choice_count; } }
choice_count++;
}
/* * Complain about zero-length choices. * They aren't useful, and handling them properly is annoying. */
if ( choice_count == 0 ) parser_error( "choice command has no symbols", $1 );
/* * Complain about funky default values. */
if ( match_exact > 1 || ( match_exact == 0 && match_partial > 1 ) ) parser_error( "choice command default value matches multiple values", $1 );
if ( match_exact == 0 && match_partial == 0 ) parser_error( "choice command default value matches no values", $1 );
/* * Cons up a node. */
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_nchoice; $$->sn_prompt = $2; $$->sn_choice_list = choice_list; $$->sn_choice_count = choice_count; $$->sn_choice_index = default_index; $$->sn_default_index = default_index; }
/* * Here is a better syntax for choice lists: * * NCHOICE prompt symdefault prompt symbol prompt symbol prompt symbol ... * * This is what the ARM processor choice would look like as an nchoice: * * $1 nchoice * $2 'ARM system type' * $3 CONFIG_ARCH_RPC * $4 'Archimedes' CONFIG_ARCH_ARC \ * 'A5000' CONFIG_ARCH_A5K \ * 'RiscPC' CONFIG_ARCH_RPC \ * 'EBSA-110' CONFIG_ARCH_EBSA110 \ * 'Footbridge-based' CONFIG_FOOTBRIDGE * * Note that this allows prompts to have spaces in them, which would make * x86 processor type a lot more readable. */
statement: NCHOICE prompt symbol choice_list '\n' { symbol_type * symbol; int choice_count; int default_index; /* this is true ... */ parser_warning( "nchoice command is not compatible with old interpreters", $1 );
for ( symbol = $4->symbol_first, choice_count = 0, default_index = -1; symbol != NULL; symbol = symbol->next, ++choice_count ) { if ( symbol->type == type_unset ) symbol->type = type_nchoice_slave; else parser_error( "nchoice command re-defines %.*s", $1, symbol->name.len, symbol->name.ptr);
if ( $3->name.len == symbol->name.len && memcmp( $3->name.ptr, symbol->name.ptr, symbol->name.len ) == 0 ) { default_index = choice_count; } }
if ( choice_count == 0 ) parser_error( "nchoice command has no symbols", $1 );
if ( default_index == -1 ) parser_error( "nchoice command has bad default symbol", $1 );
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->verb = verb_nchoice; $$->sn_prompt = $2; $$->sn_choice_list = $4; $$->sn_choice_count = choice_count; $$->sn_choice_index = default_index; $$->sn_default_index = default_index; }
/* * Expression. */
expr: expr_not { $$ = $1; }
expr_not: expr_or { $$ = $1; }
expr_not: '!' expr_not {
$$ = grab_memory( sizeof(*$$) ); $$->op = op_not; $$->word_left = NULL; $$->word_right = NULL; $$->expr_left = $2; $$->expr_right = NULL; }
expr_or: expr_and { $$ = $1; }
expr_or: expr_or DASH_O expr_and { $$ = grab_memory( sizeof(*$$) ); $$->op = op_or; $$->word_left = NULL; $$->word_right = NULL; $$->expr_left = $1; $$->expr_right = $3; }
expr_and: expr_predicate { $$ = $1; }
expr_and: expr_and DASH_A expr_predicate { $$ = grab_memory( sizeof(*$$) ); $$->op = op_and; $$->word_left = NULL; $$->word_right = NULL; $$->expr_left = $1; $$->expr_right = $3; }
expr_predicate: expr_word { $$ = $1; }
expr_predicate: word '=' word { if ( $1->literal.len >= 0 && $3->literal.len >= 0 ) parser_warning( "operator '=' has two literal operands", $2 );
$$ = grab_memory( sizeof(*$$) ); $$->op = op_equal; $$->word_left = $1; $$->word_right = $3; $$->expr_left = NULL; $$->expr_right = NULL; }
expr_predicate: word '!' '=' word { if ( $1->literal.len >= 0 && $4->literal.len >= 0 ) parser_warning( "operator '!=' has two literal operands", $2 );
$$ = grab_memory( sizeof(*$$) ); $$->op = op_not_equal; $$->word_left = $1; $$->word_right = $4; $$->expr_left = NULL; $$->expr_right = NULL; }
expr_word: word { parser_warning( "naked word in conditional expression", $1->input_point );
$$ = grab_memory( sizeof(*$$) ); $$->op = op_word; $$->word_left = $1; $$->word_right = NULL; $$->expr_left = NULL; $$->expr_right = NULL; }
/* * Choice list. */
choice_list: { $$ = grab_memory( sizeof(*$$) ); $$->prompt_first = NULL; $$->prompt_last = NULL; $$->symbol_first = NULL; $$->symbol_last = NULL; }
choice_list: choice_list prompt symbol { $$ = $1;
if ( $$->prompt_first == NULL ) $$->prompt_first = $2; if ( $$->prompt_last != NULL ) $$->prompt_last->next = $2; $$->prompt_last = $2;
if ( $$->symbol_first == NULL ) $$->symbol_first = $3; if ( $$->symbol_last != NULL ) $$->symbol_last->next = $3; $$->symbol_last = $3; }
/* * Symbol list for unset. */
unset_list: { $$ = grab_memory( sizeof(*$$) ); $$->symbol_first = NULL; $$->symbol_last = NULL; }
unset_list: unset_list symbol { $$ = $1;
if ( $$->symbol_first == NULL ) $$->symbol_first = $2; if ( $$->symbol_last != NULL ) $$->symbol_last->next = $2; $$->symbol_last = $2; }
/* * Prompt. */
prompt: LEXEME { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->value = $1.piece; }
prompt: word_dquote { if ( $1->literal.len < 0 ) parser_error( "prompt must have literal value", $1->input_point );
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->value = $1->literal; }
/* * Symbol. */
symbol: LEXEME { if ( $1.squote ) { char * buffer = grab_memory( $1.piece.len + 64 ); sprintf( buffer, "'%.*s': symbol may not be quoted.", $1.piece.len, $1.piece.ptr ); parser_error( buffer, $1.piece.ptr ); }
if ( $1.piece.len < 7 || memcmp( $1.piece.ptr, "CONFIG_", 7 ) != 0 ) { char * buffer = grab_memory( $1.piece.len + 64 ); sprintf( buffer, "'%.*s': bad symbol name (must be CONFIG_*).", $1.piece.len, $1.piece.ptr ); parser_warning( buffer, $1.piece.ptr ); }
$$ = symbol_create( $1.piece ); /* scope_define( $$ ); */ }
/* * An extra_word_list eats up extra words at the end of a command. * These values are not used (in fact I could just leak them away); * but a non-empty extra_word_list warrants a warning. */
extra_word_list: { $$ = grab_memory( sizeof(*$$) ); $$->first = NULL; $$->last = NULL; }
extra_word_list: extra_word_list word { $$ = $1; if ( $$->first == NULL ) $$->first = $2; if ( $$->last != NULL ) $$->last->next = $2; $$->last = $2; }
/* * A word can be a single atom or a double-quoted list of atoms. If every atom * in a word is literal, the word is literal, and I compute the literal value * here. Note that some semantic constructs require literal values (such as * the SOURCE command). */
word: atom_literal { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->input_point = $1->lexeme.piece.ptr; $$->dquote = 0; $$->literal = $1->lexeme.piece; $$->atom_first = NULL; }
word: atom_variable { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->input_point = $1->lexeme.piece.ptr; $$->dquote = 0; $$->literal.ptr = NULL; $$->literal.len = -1; $$->atom_first = $1; }
word: word_dquote { $$ = $1; }
word_dquote: '"' atom_list '"' { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->input_point = $1; $$->dquote = 1;
if ( ! $2->is_literal ) { /* contains a variable word */ $$->literal.ptr = NULL; $$->literal.len = -1; $$->atom_first = $2->first; } else { const atom_type * atom; int size; char * ptr_value; char * ptr;
/* calculate the size */ for ( atom = $2->first, size = 0; atom != NULL; atom = atom->next ) size += atom->lexeme.piece.len; /* synthesize a value */ ptr_value = grab_memory( size ); for ( atom = $2->first, ptr = ptr_value; atom != NULL; atom = atom->next ) { memcpy( ptr, atom->lexeme.piece.ptr, atom->lexeme.piece.len ); ptr += atom->lexeme.piece.len; }
$$->literal.ptr = ptr_value; $$->literal.len = size; $$->atom_first = NULL; } }
/* * An atom list is a list of atoms. I track whether the list contains * any variable atoms. */
atom_list: { $$ = grab_memory( sizeof(*$$) ); $$->is_literal = 1; $$->first = NULL; $$->last = NULL; }
atom_list: atom_list atom_literal { $$ = $1; if ( $$->first == NULL ) $$->first = $2; if ( $$->last != NULL ) $$->last->next = $2; $$->last = $2; }
atom_list: atom_list atom_variable { $$ = $1; $$->is_literal = 0; if ( $$->first == NULL ) $$->first = $2; if ( $$->last != NULL ) $$->last->next = $2; $$->last = $2; }
/* * An atom is either a lexeme or a $lexeme. * Lexemes come in two flavors: xxx or 'xxx yyy zzz ...'. */
atom_literal: LEXEME { $$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->lexeme = $1; $$->dollar = 0; }
atom_variable: '$' LEXEME { if ( $2.squote ) parser_error( "$'...' not allowed.", $1 );
/* yes, people have done this in the corpus! */ if ( $2.piece.len == 4 && memcmp( $2.piece.ptr, "arch", 4 ) == 0 ) { parser_warning( "'$arch' not supported in old interpreters; use '$ARCH' instead.", $1 ); }
$$ = grab_memory( sizeof(*$$) ); $$->next = NULL; $$->lexeme = $2; $$->dollar = 1;
/* scope_use( $$->value ); */ }
/* * The little language in defconfig and .config files. * This is a very simple language with just two statements: * * # CONFIG_FOO is not set * CONFIG_BAR=word * * These values are the -old- values of the symbols. The distinction between * -old- and -new- is still a little mystical. * * But all I have to do is parse. */
start_language: COOKIE_DEF_CONFIG def_line_list { parser_def_line_list = $2; }
def_line_list: { $$ = grab_memory( sizeof(*$$) ); $$->first = NULL; $$->last = NULL; }
def_line_list: def_line_list def_line { $$ = $1; if ( $$->first == NULL ) $$->first = $2; if ( $$->last != NULL ) $$->last->next = $2; $$->last = $2; }
def_line_list: def_line_list '\n' { $$ = $1; }
def_line: symbol '=' word '\n' { if ( $3->literal.len < 0 ) parser_error( "symbol value must be literal", $2 );
$$ = grab_memory( sizeof(*$$) ); $$->symbol = $1; $$->value = $3->literal; }
def_line: ISNOTSET '\n' { if ( $1.piece.len < 7 || memcmp( $1.piece.ptr, "CONFIG_", 7 ) != 0 ) { char * buffer = grab_memory( $1.piece.len + 64 ); sprintf( buffer, "'%.*s': bad symbol name (must be CONFIG_*).", $1.piece.len, $1.piece.ptr ); parser_warning( buffer, $1.piece.ptr ); }
$$ = grab_memory( sizeof(*$$) ); $$->symbol = symbol_create( $1.piece ); $$->value = piece_n; } - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |