【问题标题】:Having trouble writing tokenizer编写分词器时遇到问题
【发布时间】:2013-11-06 15:14:07
【问题描述】:

我正在用 C++ 编写一个分词器。它要做的是在文件中搜索包含在“”中的字符串字符以及符号 [ 和 ]。它将为其创建一个标记对象,并将其存储在一个向量中。它应该通过调用 input.get() 来忽略所有空白字符以跳过它们,但我不确定这是执行此操作的正确方法。我也觉得我可能犯了愚蠢的错误,比如 == 而不是 =。这是我当前的代码

vector<Token> tokenize(wstring file)
{
    ifstream input = ifstream(file);
    vector<Token> tokens;

    while(input.peek() != std::char_traits<char>::eof())
    {
        wchar_t ch = (wchar_t) input.peek();

        if (isspace(ch)) 
        {
            input.get();
        }
        else if(ch == '[' || ch == ']')
        {
            input.get();
            wstring str(&ch);
            tokens.push_back(Token(SYMBOL, str));
        }
        else if (ch == '"') 
        { 
            wstringstream accum; 
            input.get();

            while(input.peek() != '"')
            {
                if(input.peek() == std::char_traits<char>::eof())
                    endProgram(L"Unterminated String Literal");

                accum<<input.peek();
                input.get();
            }

            tokens.push_back(Token(STRING, accum.str()));
        }
    }

    for(int i = 0; i < tokens.size(); i++)
    {
        wcout<<tokens.at(i).getData()<<endl;
    }

    return tokens;
}

但是,当我在这样的文件上运行此代码时

] ]
"ddsd"

"sdsd"

[[]]]]][[

我收到错误 UnterminatedStringLiteral 我做错了什么?顺便说一下,我是 C++ 新手,所以一个简单的解释会很好。

【问题讨论】:

  • 注意in.peek()的失败结果拼写为std::char_traits&lt;char&gt;::eof()而不是-1。尽管-1 是一个通常使用的值,但并不要求该值是-1
  • else if (ch = '"') 你能看到吗? ;)
  • 已修复,但仍然出现错误

标签: c++ io tokenize


【解决方案1】:

添加更多“令牌”时,您的代码可能会变得更加复杂。
我建议要么使用switch 声明:

switch (ch)
{
    case '[':
        //...
        break;
    case ']':
        //...
        break;
// ...
    default:
        //...
        break;
};

或者使用带有函数指针的查找表:

  typedef (void)(*Function_Pointer_Type)(char ch);
  struct Lookup_Table_Entry
  {
     char   token;
     Function_Pointer_Type token_processor_func;
  };

  static const Lookup_Table_Entry  token_table[] =
  {
    { '[', Open_Bracket_Handler},
    { ']', Close_Bracket_Handler},
    { '\"', String_Delimiter},
  };
  static const unsigned int    token_table_size =
    sizeof(token_table) / sizeof(token_table[0]);

  //...
  for (unsigned int i = 0; i < token_table_size; ++i)
  {
     if (ch == token_table[i].token)
     {
        token_table[i].token_processor_func(ch);
        break;
     }
  }

这两个代码片段都更简洁,可以处理字符不是标记的情况。

如果添加更多标记,表查找可以更轻松地扩展代码。

【讨论】:

    【解决方案2】:

    我编写了这样的代码..

      ///    if(*parm_data == ' ' || *parm_data == ';' || *parm_data == '|' 
         //   || *parm_data == '\t' || *parm_data == ',') break; 
    
            char *CHXLog::GetToken(char *parm_data, char *parm_token)
            {
                while(*parm_data != 0 && *parm_data != '\n')
                { 
    
                    if( *parm_data == ',' )
                    {       
                        break; 
                    }
                    else 
                    {
                        *parm_token =*parm_data; 
                    }
                    parm_data++; 
                    parm_token++; 
                } 
    
                *parm_token = '\0'; 
    
                return parm_data + 1; 
    
            }
    

    【讨论】:

    • 我不确定我理解你在做什么,我不明白这与我的原始代码有什么关系
    【解决方案3】:

    我在这段代码中发现了我的问题,

            while(input.peek() != '"')
            {
                if(input.peek() == std::char_traits<char>::eof())
                    endProgram(L"Unterminated String Literal");
    
                accum<<input.peek();
                input.get();
            }
    
            tokens.push_back(Token(STRING, accum.str()));
    

    应该有一个

    input.get();
    

    跳过 " 字符

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-15
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      相关资源
      最近更新 更多