0

我尝试使用 C 本身来计算 C 程序中存在的标签数量。它运作良好。我扩展了它,我有一个数组ca[],其中包含行号作为元素。读取相应行时,不应在该行中搜索标签。这背后的概念是,我将从另一个程序接收一个数组,其中包含注释行的行号。因此,我将数组作为输入,并跳过单独处理这些行。

我试过的是,

int nl=0,flag=0,i=1,j=0;
int ca[100]={3,5};
char c;

fp=fopen("chumma.c","r");

while((c=getc(fp))!=EOF)
{
if(c=='\n')
    i=i+1;
if((ca[j])!=i)
{

    if(c==':')
        flag=1;

    else if((flag==1) && (c=='\n'))
    {      
      flag=0;nl++;
    }

}
else
   j++;
}

nl是标签的数量。这不会检查线路本身。请指导我哪里出错了。

4

2 回答 2

2

这听起来像是家庭作业/学习练习,所以我将解释计划/设计这样的程序的过程。然后我会给你一个实现它的方法的示例。

编写此类程序的一种方法是构建一对状态机:

  1. 初始状态/空白状态
  2. 从状态1:已经看到/*序列;保持这种状态直到*/;返回 1
  3. 从状态1:见过"性格;保持这种状态直到\";返回 1
  4. 从状态1:已经看到//序列;保持这种状态直到换行;返回 1
  5. 从状态1:看到一封信;保持这种状态捕获直到非字母和非数字
  6. 从状态 1:看到其他任何东西,保持这种状态直到换行。
  7. 从状态 3:已经看到\提取下一个字符,然后返回状态 3

一旦离开状态 5:

  • 如果这个词是switch我们将进入我们的另一个状态机(如下)。
  • 如果我们没有看到:,则返回状态 1
  • 否则我们的话就是一个标签;用它做任何你想做的事情并返回到状态 1。

但是,当我们看到switch时,由于紧随其后的表达式,我们需要另一个状态表:

  1. 初始状态/空白
  2. 从状态 1:(在开始之后switch
  3. 从状态 1:所有其他字符生成错误
  4. 从状态 2:/*并被"视为状态机 1(上图)
  5. 从状态 2:)看到
  6. 从状态 5:{- 增加嵌套级别并立即进入状态 7。
  7. 空白/状态
  8. 从状态 7 开始:}- 在进入该状态时降低嵌套级别;如果嵌套级别为零,则在第一个状态机中返回状态 1,否则保持状态 7。
  9. 从状态 7:看到一封信;保持这种状态捕获直到非字母或:
  10. 从状态 7:看到其他任何东西,保持在这个状态直到;}分别移动到状态 7 和 8。

一旦离开状态 9:

  • 如果我们没有看到:然后转到状态 10
  • 否则如果单词 asdefault则进入状态 10
  • 否则这是一个标签;用它做任何你想做的事情,然后进入状态 10

下一步是为每个状态编写一个函数。给状态编号并给函数编号可能会有所帮助。他们对“字符”或“字符序列”的操作方式通常是我早期写的一些低级的东西:

int c;
int next() { c=getchar(); return c; }
typedef int (*state)();

例如,上面的状态 2 和 3 可以写成:

state state2() { if(c == '*' && next() == '/') return state1; return state2; }
state state3() { if(c == '"') return state1; if (c == '\\') return state7; }

算出其余的州应该很容易。状态 5 将有一个缓冲区,您正在填充该缓冲区以“读取”单词:

char word[600];
int ptr;
state state5() { 
  ptr = 0;
  while(isdigit(c) || isalpha(c)) {
    word[ptr] = c;
    ptr++;
    if(ptr==600)abort();
    next();
  }
  /* now leaving state 5 */
}

完成此操作后,您可以编写驱动程序:

void statemachine1() {
  state x = state1;
  while(c != -1) x = x();
}

如果您犯了错误,拥有一些调试工具会很有帮助。一个好的方法是在数组中标记每个状态:

state statelist1[] = { state1, state2, state3, state4, state5, state6, state7 };
int statenumber(state x) {
  int i, n = sizeof(statelist1) / sizeof(state);
  while(n-->0) if(x == statelist1[n]) return n;
  abort();
}

这在调试时会很有帮助;我可能会插入:

printf("state = %d, char = %02x (%c)\n", statenumber(x), c,c);

进入驱动程序循环,如下所示:

printf("char = %02x (%c)\n", c,c);

在我追踪机器的各个部分。这将在我的脑海中更牢固地建立状态机地图,并且当我沿着我的测试程序跟踪它时,它将更容易验证所有状态。

如果事情开始变得困难,我将修改next()以跟踪当前行:

int line = 1;
int next() { c=getchar(); if(c == '\n') line++; return c; }

这样我也可以在我的printf()陈述中使用它。

一旦我对一切正常工作感到满意,我将删除调试代码。

祝你好运!

于 2012-12-25T08:16:38.950 回答
1

试试这个,,

int nl=0,flag=0,i=1,j=0;
int ca[100]={3,5};
char c;

fp=fopen("Kiss.c","r");

while ((c=getc(fp))!=EOF) {

if (c == '\n') {
    if (ca[j] == i) j ++;

    if (flag == 1) {      
        flag = 0; nl ++;
    }

    i = i ++;
    continue;
}

if (ca[j] == i)
    continue;

if (c==':')
    flag=1;
于 2012-12-25T08:22:57.513 回答