早些时候我正在为我的解析器修复词法分析器;现在我必须为它创建一个验证器。我的想法是使用以下预处理器宏将枚举常量转换为字符串:#define MACRO_STRINGIFY(x) #x
。
然后我做了一个函数来比较各种令牌值,我做了三个,但它们都是一样的,只有一些小的改动):
unsigned int compare_keyword( enum script_keywords keyword, char *token ) {
char *temporary = MACRO_STRINGIFY( keyword );
unsigned int i = 0;
for (; i < (strlen( "KEYWORD_" ) + 1); i++) {
++temporary;
}
// 0 on match, 1 on no match
return strcmp( temporary, token ) ? 1 : 0;
}
现在,这个功能绝对正常... 当关键字是枚举常量时:
void test() {
printf( "\nIF is " );
// Finish the sentence based on the return value
compare_keyword( KEYWORD_IF, "IF" ) ? printf( "not a keyword.\n" ) : printf( "a keyword.\n" );
}
test(); //--> Outputs 'IF is a keyword' like expected.
另一方面,如果我传递一个像1这样的值(符号枚举常量KEYWORD_IF解析为的值),则该函数不能按预期工作。
// Same as last time with one edit:
void test() {
/* See above code with following change on line 4 */
compare_keyword( 1, "IF" ) /* etc... */
/* Rest of code from previous test */
}
test(); //--> Outputs 'IF is not a keyword' even if KEYWORD_IF resolves to the value 1.
我在这里得到的一点是,preproccessor是非常文字的,我更喜欢使用for循环来有效地循环遍历常量而不会使代码大小膨胀(如果我最终使用的话会发生这种情况)枚举常量)。因此,问题是我如何使用switch…case…
或if…else…
将纯整数值转换为符号名称而不是?
编辑:枚举详细信息:
enum script_keywords {
KEYWORD_IF = 1,
KEYWORD_THEN = 2,
KEYWORD_ELSEIF = 3,
KEYWORD_ELSE = 4,
KEYWORD_ENDIF = 5,
KEYWORD_FOR = 6,
KEYWORD_TO = 7,
KEYWORD_STEP = 8,
KEYWORD_EXITFOR = 9,
KEYWORD_NEXT = 10,
KEYWORD_LOOP = 11,
KEYWORD_WHILE = 12,
KEYWORD_EXITLOOP = 13,
KEYWORD_ENDLOOP = 14,
KEYWORD_DO = 15,
KEYWORD_EXITDO = 16,
KEYWORD_UNTIL = 17,
KEYWORD_ON = 18,
KEYWORD_GOTO = 19,
KEYWORD_CALL = 20,
KEYWORD_LET = 21,
KEYWORD_DIM = 22,
KEYWORD_AS = 23
};
答案 0 :(得分:0)
The Macro&#34; MACRO_STRINGIFY&#34;由预处理器在编译时进行评估。它将返回参数的实际名称,所以
MACRO_STRINGIFY(keyword) -> "keyword"
MACRO_STRINGIFY(KEYWORD_IF) -> "KEYWORD_IF"
MACRO_STRINGIFY(1) -> "1"
显然这不会导致任何解决方案。
相反,可以使用编译时生成的键值映射来实现此类功能:
struct map
{
int key;
const char* value;
};
struct map mappings[] =
{
{ KEYWORD_IF, "IF" },
{ KEYWORD_ELSE, "ELSE" }
};
然后在运行时简单地迭代这些映射条目以找出你需要的东西:
static int is_keyword(const char* str)
{
int i;
const int count = sizeof(mappings) / sizeof(mappings[0]);
for(i = 0; i < count; i++)
{
struct map* m = &mappings[i];
if(strcmp(str, m->value) == 0)
{
return 1;
}
}
return 0;
}
void test()
{
const char* str = "IF";
const char* what;
if(is_keyword(str))
{
what = "a keyword";
}
else
{
what = "not a keyword";
}
printf("%s is %s.\n", str, what);
}
这可能是最小的。可执行二进制文件通常不包括从例如已知的枚举值的名称。 Java的。
为了进一步扩展,你可以做一些预处理器voodoo自动生成映射数组(半)。但由于我不是预处理器伏都教的大朋友,我会跳过它;)