C++ 扫描的测试文件的最后一个字符是在它实际上不在的行上输出的

C++ 扫描的测试文件的最后一个字符是在它实际上不在的行上输出的,c++,compiler-construction,C++,Compiler Construction,晚上好,我正在为一个编译器课程做扫描仪。我有一个测试文件,我们必须扫描,打印令牌所在的行,令牌是什么以及它的id号。除了testfile中的最后一个字符(句点)外,程序工作正常。该周期实际上在第17行,但我的扫描仪将其与EOF令牌一起输出到第18行。我试着看一双新的眼睛是否能看到我所缺少的东西。所有其他令牌在其各自的行上输出。让我给你扫描仪本身。扫描仪中还有几个其他功能,但我认为这个问题不需要它们 void scanner(FILE *file) { const int FINAL_STATE

晚上好,我正在为一个编译器课程做扫描仪。我有一个测试文件,我们必须扫描,打印令牌所在的行,令牌是什么以及它的id号。除了testfile中的最后一个字符(句点)外,程序工作正常。该周期实际上在第17行,但我的扫描仪将其与EOF令牌一起输出到第18行。我试着看一双新的眼睛是否能看到我所缺少的东西。所有其他令牌在其各自的行上输出。让我给你扫描仪本身。扫描仪中还有几个其他功能,但我认为这个问题不需要它们

void scanner(FILE *file) {
const int FINAL_STATE = -1, ERROR_STATE = -2;
char next_char;
static int line_count = 1;
string s = "";
int next_state, state = 0;

while(state != FINAL_STATE) {
  next_char = get_char(file);

  // deal with comments
  if(next_char == '&') {
     next_char = get_char(file);
     while(next_char != '\n') {
        next_char = get_char(file);
        if (next_char == '\n') {
            line_count++;
        }
     }
     continue;
  }

  // count lines
  if(next_char == '\n') {
     line_count++;
  }

  // deal with EOF
  if(next_char == EOF) {
     tk.lexeme = "EOF";
     tk.tk_num = eof_tk;
     tk.line_num = line_count;
     return;
  }
  next_state = table[state][c_val(next_char)];
  if(next_state == ERROR_STATE) {
     cout << "error on line [" << line_count << "]\n";
     exit(0);
  }

  // deal with final state         <------------I think my problem is here
  if(next_state == FINAL_STATE) {
     if(!isspace(next_char)) {
        ungetc(next_char, file);
     }

     if(table[state][1] == id_tk) {
        for(int t = 0; t < size(keywords); t++) {
           if(keywords[t].compare(s) == 0) {
              tk.lexeme = s;
              tk.tk_num = key_assign(t);
              tk.line_num = line_count;
              return;
           }

           else {
              tk.lexeme = s;
              tk.tk_num = id_tk;
              tk.line_num = line_count;
           }
        }

     if(tk.lexeme == "") {
        tk.lexeme = s;                                              
     }
     }

     else {
        tk.lexeme = s;                                      // string
        tk.tk_num = (token_type)table[state][1];            // type
        tk.line_num = line_count;                           // line
     }

     return;
  }

  state = next_state;

  if(!isspace(next_char)) {
     s += next_char;
  }
 }
}
void扫描器(文件*FILE){
const int FINAL_STATE=-1,ERROR_STATE=-2;
char next_char;
静态整数行计数=1;
字符串s=“”;
int next_state,state=0;
while(状态!=最终状态){
下一个字符=获取字符(文件);
//处理评论
如果(下一个字符=='&'){
下一个字符=获取字符(文件);
while(下一个字符!='\n'){
下一个字符=获取字符(文件);
如果(下一个字符=='\n'){
行数++;
}
}
持续
}
//数行
如果(下一个字符=='\n'){
行数++;
}
//处理EOF
if(next_char==EOF){
tk.lexeme=“EOF”;
tk.tk_num=eof_tk;
tk.line\u num=行数;
回来
}
next_state=表[状态][c_val(next_char)];
如果(下一个状态==错误状态){

因为
之后的下一个字符是
\n
(大多数文本编辑器在文件末尾输入一个隐藏的换行符),所以在打印结果之前,扫描仪似乎正在增加行号。行数是否过早增加


我会尝试从文件中删除最后一个
\n
,看看这是否会改变结果看起来您的扫描仪在打印结果之前正在增加行号,因为
之后的下一个字符是
\n
(大多数文本编辑器在文件末尾输入隐藏的换行符)行计数过早增加


我会尝试从文件中删除最后一个
\n
,看看这是否会改变结果

@diclop这很好地解释了您的一个问题

(尽管未显示
get\u char()
,但假设它类似于
getchar()

  • EOF的错误测试

    if(next_char==EOF){
    是错误的。
    next_char
    使用type
    char
    ,而EOF是type
    int
    。您可以读取与EOF具有相同8位模式且不是EOF的字节,并在错误的字节上退出。通过使用
    int next_char
    并确保
    get_char()
    返回类似于
    getchar()

  • 2.势无限循环

    如果
    “&”
    是文件中的最后一个字节,则不会退出此循环

    if(next_char == '&') {
      next_char = get_char(file);
      while(next_char != '\n') {
        ...
        }
     }
    
    3.错误的
    eof()
    test。如果在尝试读取超过最后一个字节的数据后,文件没有更多数据,则返回true

    while(!feof(fp)) {
    
    推荐一个习惯用语

    int next_char;
    while((next_char = get_char()) != EOF) {
      ...
    

    @迪克洛菲斯很好地解释了你的一个问题

    (尽管未显示
    get\u char()
    ,但假设它类似于
    getchar()

  • EOF的错误测试

    if(next_char==EOF){
    是错误的。
    next_char
    使用type
    char
    ,而EOF是type
    int
    。您可以读取与EOF具有相同8位模式且不是EOF的字节,并在错误的字节上退出。通过使用
    int next_char
    并确保
    get_char()
    返回类似于
    getchar()

  • 2.势无限循环

    如果
    “&”
    是文件中的最后一个字节,则不会退出此循环

    if(next_char == '&') {
      next_char = get_char(file);
      while(next_char != '\n') {
        ...
        }
     }
    
    3.错误的
    eof()
    test。如果在尝试读取超过最后一个字节的数据后,文件没有更多数据,则返回true

    while(!feof(fp)) {
    
    推荐一个习惯用语

    int next_char;
    while((next_char = get_char()) != EOF) {
      ...
    

    如何从文件中删除“\n”字符,尤其是隐藏的字符?我在创建文件时使用了VIM编辑器,并确保没有在文件中添加换行符。VIM会自动添加最后一个\n字符,因为用换行符结束文本文件是常见的礼貌行为。您可以关闭此行为或使用其他文本编辑器。但是,我建议您最好修复您的程序以便能够处理它。如何从文件中删除“\n”字符,尤其是隐藏的字符?我在创建文件时使用了VIM编辑器,并确保没有在文件中添加换行符。VIM会自动添加最后一个\n字符,因为用换行符结束文本文件是常见的礼貌行为。您可以关闭此行为或者使用另一个文本编辑器。不过,我建议你最好修复你的程序,以便能够处理它。根据教授的说法,注释以
    '和'
    开头,以
    '\n'
    结尾。我很欣赏潜在的无限循环,并看看你将如何处理它。我试图避免阅读一个我喜欢的字符因此,
    while(!feof(fp));
    @Clint不建议在main()
    中读取字符。相反,在
    main()`
    int Go;do{Go=scanner(fp);printf(…);}while(Go);
    和在
    scanner(fp)
    中执行
    while((next_char=get_char())!=EOF)
    。打得好!我也在考虑“解析”main中的注释,但这只是一个小部分或更大的项目。我们很快就要开始解析和语义了。我意识到扫描仪需要“完美”才能让其他项目正常工作。感谢您的帮助!您已经“检查”过了还感谢diclophis!您的建议非常好,但我有一个问题。我的scanner函数是void类型,因为有几个返回。If
    go=scanner(fp)
    我收到一个编译错误
    error:void value未被忽略,因为它应该是
    。当然,如果我将scanner函数更改为int,我需要为scanner函数中的所有返回语句设置值。