由字符串无法正确读取的任何字符分隔的值

时间:2018-04-21 06:57:10

标签: c string strcmp strcpy

由于我的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;
}

1 个答案:

答案 0 :(得分:-1)

  

我做错了什么?

使用自定义解决方案解决问题,而不使用通常用于解决问题的任何已知模式,因为这是一个已知问题。

这是一个解析问题,因此您需要一个状态机将令牌放入符号表中,然后在看到它们时增加符号计数。在程序结束时,检查计数为零的符号,它们是未使用的符号。

struct symbol_s {
    char *name;
    size_t count;

    struct symbol_s *next;
};

此结构是namecount对的列表,足以跟踪看到的符号数。

解析时的一个区别是符号的声明(或第一次使用)及其后续使用。在您的示例中,我们可以将声明定义为后跟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和更高级别的语言可以更轻松地完成此操作。