由于我的8051编译器没有检测未使用变量的功能,我决定尝试实现自己的变量,但它不起作用。
当程序运行时,它通过读取主文件成功识别所有标签,然后对于每个标签名称,它扫描整个文件,对于扫描的每一行,调用以下函数:
findlabel(labelname,fileline);
执行程序时,它错误地将以下变量标识为未使用:
PQR,MNO,TUV和null
我正在连续扫描此程序的文件具有以下内容:
ABC equ 1h
GHI equ 2h
JKL equ 3h
TUV equ 6h
MNO equ 4h
PQR equ 5h
cjne A,#ABC,def
mov GHI,#1h
mov JKL,MNO
def:
但MNO用于" mov JKL,MNO"线。
我也试过修剪回车和额外的间距,这没有用。
我做错了什么?
源代码如下:
void trim(char* astr){
while (astr[0]==' ' || astr[0]=='\r'|| astr[0]=='\t' || astr[0]=='\n'){
strcpy(astr,astr+1);
}
int sz=strlen(astr)-2;
while(astr[sz]==' ' || astr[sz]=='\r'|| astr[sz]=='\t' || astr[sz]=='\n'){
astr[sz]='\0';sz--;
}
}
int findlabel(char* lbl,char*fline){
int par,isdec=0;
char* semicolon=strcasestr(fline,";");
char* qs=strcasestr(fline,"';'");
if (semicolon && !qs){
//strip everything after semicolon if not quoted
memcpy(fline,fline,semicolon-fline);
fline[semicolon-fline]='\0';
}
trim(fline);
char* spc=strcasestr(fline," "); //Make sure there's a space inbetween text
if (spc){
strcpy(fline,spc+1); // toss out command
trim(fline);
for (par=1;par<=3;par++){
char ilbl[2000];
char* comma=strcasestr(fline,",");
if (comma){
//found comma so strip it and save parameter to ilbl
memcpy(ilbl,fline,comma-fline);
ilbl[comma-fline]='\0';
strcpy(fline,comma+1);
}else{
//no comma so run this loop one more time with last part of file line as parameter
strcpy(ilbl,fline);par=99;
}
trim(ilbl);
if (strcasecmp(ilbl,lbl)==0){isdec=1;par=99;} //first param = #label
if (ilbl[0]=='#'){
strcpy(ilbl,ilbl+1);
if (strcasecmp(ilbl,lbl)==0){isdec=1;par=99;} //first param = label
}
}
}
return isdec;
}
答案 0 :(得分:-1)
我做错了什么?
使用自定义解决方案解决问题,而不使用通常用于解决问题的任何已知模式,因为这是一个已知问题。
这是一个解析问题,因此您需要一个状态机将令牌放入符号表中,然后在看到它们时增加符号计数。在程序结束时,检查计数为零的符号,它们是未使用的符号。
struct symbol_s {
char *name;
size_t count;
struct symbol_s *next;
};
此结构是name
和count
对的列表,足以跟踪看到的符号数。
解析时的一个区别是符号的声明(或第一次使用)及其后续使用。在您的示例中,我们可以将声明定义为后跟equ
字符串的任何符号。稍后可以对其进行扩展或修改以包括其他类型,例如标签。
尽管如此,一个相当笨拙的实现可以写成:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
const char *source = " \
ABC equ 1h \
GHI equ 2h \
JKL equ 3h \
TUV equ 6h \
MNO equ 4h \
PQR equ 5h \
\
cjne A,#ABC,def \
mov GHI,#1h \
mov JKL,MNO \
def: \
";
struct symbol_s {
char *name;
size_t count;
struct symbol_s *next;
};
void symbol_append_child(struct symbol_s *head, struct symbol_s *next)
{
struct symbol_s *it;
assert(head != NULL);
assert(next != NULL);
it = head;
while (it->next != NULL && (it = it->next)) { }
it->next = next;
}
struct symbol_s *symbol_new(char *name)
{
struct symbol_s *symbol;
assert(name != NULL);
symbol = calloc(1, sizeof(*symbol));
symbol->name = strdup(name);
return symbol;
}
void symbol_free(struct symbol_s *symbol)
{
free(symbol->name);
free(symbol);
}
int main()
{
int cursor = 0;
int c;
struct symbol_s head = { 0 };
while ((c = source[cursor++]) != 0) {
if (isalpha(c)) {
int begin_cursor = cursor - 1;
while ((c = source[cursor++]) && isalnum(c)) {}
if (isspace(c) && strncmp("equ", source + cursor, 3) == 0) {
char buffer[512];
size_t len = cursor - begin_cursor - 1;
strncpy(buffer, source + begin_cursor, len);
buffer[len] = 0;
symbol_append_child(&head, symbol_new(buffer));
} else {
char buffer[512];
size_t len = cursor - begin_cursor - 1;
strncpy(buffer, source + begin_cursor, len);
buffer[len] = 0;
struct symbol_s *it;
for (it = &head; it != NULL; it = it->next) {
if (it->name == NULL) {
continue;
}
if (strncmp(it->name, source + begin_cursor, len) == 0) {
it->count += 1;
}
}
continue;
}
}
}
// Print unused symbols
struct symbol_s *it;
for (it = &head; it != NULL; it = it->next) {
if (it->name == NULL) {
continue;
}
if (it->count == 0) {
printf("Unused symbol: %s\n", it->name, it->count);
}
}
// clean up
struct symbol_s *prev;
for (prev = NULL, it = &head; it != NULL; prev = it, it = it->next) {
if (it->name == NULL) {
continue;
}
if (prev != NULL && prev->name) {
symbol_free(prev);
}
}
symbol_free(prev);
return 0;
}
打印哪些:
Unused symbol: TUV
Unused symbol: PQR
用于运行示例:https://ideone.com/b3KggJ
虽然提醒您,使用regexp和更高级别的语言可以更轻松地完成此操作。