📄 tkparse.c
字号:
/* * tkparse.c * * Eric Youngdale was the original author of xconfig. * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer. * * Parse a config.in file and translate it to a wish script. * This task has three parts: * * tkparse.c tokenize the input * tkcond.c transform 'if ...' statements * tkgen.c generate output * * Change History * * 7 January 1999, Michael Elizabeth Chastain, <mec@shout.net> * - Teach dep_tristate about a few literals, such as: * dep_tristate 'foo' CONFIG_FOO m * Also have it print an error message and exit on some parse failures. * * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net> * - Don't fclose stdin. Thanks to Tony Hoyle for nailing this one. * * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net> * - Steam-clean this file. I tested this by generating kconfig.tk for * every architecture and comparing it character-for-character against * the output of the old tkparse. * * 23 January 1999, Michael Elizabeth Chastain, <mec@shout.net> * - Remove bug-compatible code. * * 07 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl> * - Submenus implemented, * - plenty of option updating/displaying fixes, * - dep_bool, define_hex, define_int, define_string, define_tristate and * undef implemented, * - dep_tristate fixed to support multiple dependencies, * - handling of variables with an empty value implemented, * - value checking for int and hex fields, * - more checking during condition parsing; choice variables are treated as * all others now, * * TO DO: * - xconfig is at the end of its life cycle. Contact <mec@shout.net> if * you are interested in working on the replacement. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "tkparse.h"static struct kconfig * config_list = NULL;static struct kconfig * config_last = NULL;static const char * current_file = "<unknown file>";static int lineno = 0;static void do_source( const char * );#undef strcmpint my_strcmp( const char * s1, const char * s2 ) { return strcmp( s1, s2 ); }#define strcmp my_strcmp/* * Report a syntax error. */static void syntax_error( const char * msg ){ fprintf( stderr, "%s: %d: %s\n", current_file, lineno, msg ); exit( 1 );}/* * Find index of a specyfic variable in the symbol table. * Create a new entry if it does not exist yet. */#define VARTABLE_SIZE 2048struct variable vartable[VARTABLE_SIZE];int max_varnum = 0;int get_varnum( char * name ){ int i; for ( i = 1; i <= max_varnum; i++ ) if ( strcmp( vartable[i].name, name ) == 0 ) return i; if (max_varnum > VARTABLE_SIZE-1) syntax_error( "Too many variables defined." ); vartable[++max_varnum].name = malloc( strlen( name )+1 ); strcpy( vartable[max_varnum].name, name ); return max_varnum;}/* * Get a string. */static const char * get_string( const char * pnt, char ** label ){ const char * word; word = pnt; for ( ; ; ) { if ( *pnt == '\0' || *pnt == ' ' || *pnt == '\t' ) break; pnt++; } *label = malloc( pnt - word + 1 ); memcpy( *label, word, pnt - word ); (*label)[pnt - word] = '\0'; if ( *pnt != '\0' ) pnt++; return pnt;}/* * Get a quoted string. * Insert a '\' before any characters that need quoting. */static const char * get_qstring( const char * pnt, char ** label ){ char quote_char; char newlabel [2048]; char * pnt1; /* advance to the open quote */ for ( ; ; ) { if ( *pnt == '\0' ) return pnt; quote_char = *pnt++; if ( quote_char == '"' || quote_char == '\'' ) break; } /* copy into an intermediate buffer */ pnt1 = newlabel; for ( ; ; ) { if ( *pnt == '\0' ) syntax_error( "unterminated quoted string" ); if ( *pnt == quote_char && pnt[-1] != '\\' ) break; /* copy the character, quoting if needed */ if ( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']' ) *pnt1++ = '\\'; *pnt1++ = *pnt++; } /* copy the label into a permanent location */ *pnt1++ = '\0'; *label = (char *) malloc( pnt1 - newlabel ); memcpy( *label, newlabel, pnt1 - newlabel ); /* skip over last quote and next whitespace */ pnt++; while ( *pnt == ' ' || *pnt == '\t' ) pnt++; return pnt;}/* * Get a quoted or unquoted string. It is recognized by the first * non-white character. '"' and '"' are not allowed inside the string. */static const char * get_qnqstring( const char * pnt, char ** label ){ char quote_char; while ( *pnt == ' ' || *pnt == '\t' ) pnt++; if ( *pnt == '\0' ) return pnt; quote_char = *pnt; if ( quote_char == '"' || quote_char == '\'' ) return get_qstring( pnt, label ); else return get_string( pnt, label );}/* * Tokenize an 'if' statement condition. */static struct condition * tokenize_if( const char * pnt ){ struct condition * list; struct condition * last; struct condition * prev; /* eat the open bracket */ while ( *pnt == ' ' || *pnt == '\t' ) pnt++; if ( *pnt != '[' ) syntax_error( "bad 'if' condition" ); pnt++; list = last = NULL; for ( ; ; ) { struct condition * cond; /* advance to the next token */ while ( *pnt == ' ' || *pnt == '\t' ) pnt++; if ( *pnt == '\0' ) syntax_error( "unterminated 'if' condition" ); if ( *pnt == ']' ) return list; /* allocate a new token */ cond = malloc( sizeof(*cond) ); memset( cond, 0, sizeof(*cond) ); if ( last == NULL ) { list = last = cond; prev = NULL; } else { prev = last; last->next = cond; last = cond; } /* determine the token value */ if ( *pnt == '-' && pnt[1] == 'a' ) { if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) syntax_error( "incorrect argument" ); cond->op = op_and; pnt += 2; continue; } if ( *pnt == '-' && pnt[1] == 'o' ) { if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) syntax_error( "incorrect argument" ); cond->op = op_or; pnt += 2; continue; } if ( *pnt == '!' && pnt[1] == '=' ) { if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) syntax_error( "incorrect argument" ); cond->op = op_neq; pnt += 2; continue; } if ( *pnt == '=' ) { if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) syntax_error( "incorrect argument" ); cond->op = op_eq; pnt += 1; continue; } if ( *pnt == '!' ) { if ( prev && ( prev->op != op_and && prev->op != op_or && prev->op != op_bang ) ) syntax_error( "incorrect argument" ); cond->op = op_bang; pnt += 1; continue; } if ( *pnt == '"' ) { const char * word; if ( prev && ( prev->op == op_variable || prev->op == op_constant ) ) syntax_error( "incorrect argument" ); /* advance to the word */ pnt++; if ( *pnt == '$' ) { cond->op = op_variable; pnt++; } else { cond->op = op_constant; } /* find the end of the word */ word = pnt; for ( ; ; ) { if ( *pnt == '\0' ) syntax_error( "unterminated double quote" ); if ( *pnt == '"' ) break; pnt++; } /* store a copy of this word */ { char * str = malloc( pnt - word + 1 ); memcpy( str, word, pnt - word ); str [pnt - word] = '\0'; if ( cond->op == op_variable ) { cond->nameindex = get_varnum( str ); free( str ); } else /* op_constant */ { cond->str = str; } } pnt++; continue; } /* unknown token */ syntax_error( "bad if condition" ); }}/* * Tokenize a choice list. Choices appear as pairs of strings; * note that I am parsing *inside* the double quotes. Ugh. */static const char * tokenize_choices( struct kconfig * cfg_choose, const char * pnt ){ int default_checked = 0; for ( ; ; ) { struct kconfig * cfg; char * buffer = malloc( 64 ); /* skip whitespace */ while ( *pnt == ' ' || *pnt == '\t' ) pnt++; if ( *pnt == '\0' ) return pnt; /* allocate a new kconfig line */ cfg = malloc( sizeof(*cfg) ); memset( cfg, 0, sizeof(*cfg) ); if ( config_last == NULL ) { config_last = config_list = cfg; } else { config_last->next = cfg; config_last = cfg; } /* fill out the line */ cfg->token = token_choice_item; cfg->cfg_parent = cfg_choose; pnt = get_string( pnt, &cfg->label ); if ( ! default_checked && ! strncmp( cfg->label, cfg_choose->value, strlen( cfg_choose->value ) ) ) { default_checked = 1; free( cfg_choose->value ); cfg_choose->value = cfg->label; } while ( *pnt == ' ' || *pnt == '\t' ) pnt++; pnt = get_string( pnt, &buffer ); cfg->nameindex = get_varnum( buffer ); } if ( ! default_checked ) syntax_error( "bad 'choice' default value" ); return pnt;}/* * Tokenize one line. */static void tokenize_line( const char * pnt ){ static struct kconfig * last_menuoption = NULL; enum e_token token; struct kconfig * cfg; struct dependency ** dep_ptr; char * buffer = malloc( 64 ); /* skip white space */ while ( *pnt == ' ' || *pnt == '\t' ) pnt++; /* * categorize the next token */#define match_token(t, s) \ if (strncmp(pnt, s, strlen(s)) == 0) { token = t; pnt += strlen(s); break; } token = token_UNKNOWN; switch ( *pnt ) { default: break; case '#': case '\0': return; case 'b': match_token( token_bool, "bool" ); break; case 'c': match_token( token_choice_header, "choice" ); match_token( token_comment, "comment" ); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -