因此,我正在制作一个Rust中的lexer,它有一堆测试用例需要通过.我的Rust代码现在的问题是,当我使用字符串运行测试用例时,字符串的测试用例都不起作用.但其他令牌的测试用例正在发挥作用.

so for example if there was a test that used "hello world":
ie:

fn test_03() {
  assert_eq!(lex("hello world"),vec![Token::Alpha(b'h'), Token::Alpha(b'e'), Token::Alpha(b'l'), Token::Alpha(b'l'), Token::Alpha(b'o'), Token::WhiteSpace, Token::Alpha(b'w'), Token::Alpha(b'o'), Token::Alpha(b'r'), Token::Alpha(b'l'), Token::Alpha(b'd'), Token::EOF]);
}

测试失败,错误如下:

"线程‘test_03’在‘断言失败:(left == right)’时死机 左:[Alpha(111), WhiteSpace, Alpha(100), EOF], 右:[Alpha(104), Alpha(101), Alpha(108), Alpha(108), Alpha(111), WhiteSpace, Alpha(119), Alpha(111), Alpha(114), Alpha(108), Alpha(100), EOF]‘,测试/词汇.rs:15:3"

其中‘Right’具有正确的值,而Left是我的代码生成的值.所以基本上它是在接受‘h’,但接下来它不是读‘e’,而是直接进入空格.

我试过用PRINT语句调试小段代码,但都不起作用.我甚至try 将字符串处理 case 移到顶部,但这不起作用.任何关于我可以修改的帮助都将不胜感激,因为我是铁 rust 新手,不太确定这里可能有什么错误!

以下是我的代码:

pub enum Token {
  Keyword(Vec<u8>),
  Alpha(u8),
  Digit(u8),
  LeftParen,
  RightParen,
  LeftCurly,
  RightCurly,
  Equal,
  Plus,
  Dash,
  Quote,
  WhiteSpace,
  Semicolon,
  Comma,
  Other,
  EOF,
}

//LEX FUNCTION: 
pub fn lex(input: &str) -> Vec<Token> {
  let bytes = input.as_bytes();
  let mut tokens = vec![];
  let mut count = 0;
  while count < bytes.len() {
      let token = match bytes[count] {
          //handling string input-- not working? 
          0x22 => {
            let mut string = String::new(); // use String instead of Vec<u8>
            count += 1;
            while count < bytes.len() && bytes[count] != 0x22 {
                string.push(bytes[count] as char); // append the character to the string
                count += 1;
            }
            count += 1;
            Token::Keyword(string.into_bytes()) // convert the String back to Vec<u8>
        }
          0x41..=0x5A | 0x61..=0x7A => {
              let mut keyword = vec![bytes[count]];
              while count + 1 < bytes.len()
                  && (bytes[count + 1] >= 0x41 && bytes[count + 1] <= 0x5A
                      || bytes[count + 1] >= 0x61 && bytes[count + 1] <= 0x7A)
              {
                  keyword.push(bytes[count + 1]);
                  count += 1;
              }
              match &keyword[..] {
                  b"true" => Token::Keyword(keyword),
                  b"false" => Token::Keyword(keyword),
                  b"fn" => Token::Keyword(keyword),
                  b"return" => Token::Keyword(keyword),
                  b"let" => Token::Keyword(keyword),
                  _ => Token::Alpha(bytes[count]),
              }
          }
          0x30..=0x39 => Token::Digit(bytes[count]),
          0x28 => Token::LeftParen,
          0x29 => Token::RightParen,
          0x7B => Token::LeftCurly,
          0x7D => Token::RightCurly,
          0x3D => Token::Equal,
          0x2B => Token::Plus,
          0x2D => Token::Dash,
          0x20 | 0xA | 0x9 => Token::WhiteSpace, //whitespace error? 
          0x3B => Token::Semicolon,
          0x2C => Token::Comma,
          _ => Token::Other,
      };
      tokens.push(token);
      count += 1;
  }
  tokens.push(Token::EOF);
  tokens
}


pub fn strip_whitespace(tokens: Vec<Token>) -> Vec<Token> {
  let mut new:Vec<Token> = vec![];
  for token in tokens{
    if token != Token::WhiteSpace{
      new.push(token);
    }
  }
  return new;   
}

推荐答案

以下是您的代码正在执行的操作:

bytes[count]等于h.

let token = match bytes[count] {

这是在az之间,所以它取第二个分支.

0x41..=0x5A | 0x61..=0x7A => {

keyword将前5个字节推送到它.

keyword.push(bytes[count + 1]);

现在bytes[count + 1]是一个空格,所以第二个条件是false,While循环中断

bytes[count + 1] >= 0x41 && bytes[count + 1] <= 0x5A
    || bytes[count + 1] >= 0x61 && bytes[count + 1] <= 0x7A

keyword与任何选项都不匹配,因此它采用最后一个分支

_ => Token::Alpha(bytes[count]),

记住,bytes[count + 1]是空格,所以bytes[count]o.

推送新创建的Alpha令牌,count递增,world发生类似的事情.

您的测试用例表明,您预期这将创建几个Alpha个令牌,每个字母一个.您的代码中根本没有这样做的内容.

但是,代码中的问题文本和注释表明您希望创建一个称为字符串的Keyword.如果它做到了这一点,它也将无法通过测试,因为它预计不会有Keyword.您还需要以"个字符开始输入.您可以通过几种不同的方式在Ruust中编写"个字符的字符串.它们都包含内容"hello world",包括引号:

"\"hello world\""
r#""hello world""#

第一个是转义引号,第二个是使用原始字符串语法.

另一个不同之处是测试用例使用ASCII字节文字语法,而您在代码中没有这样做.我建议您在使用字节表示文本数据时使用ASCII字节文字.

我同意这种词法分析方法不理想的 comments .跟踪每个变量的变化并不容易,而且有很多重复的代码.首先了解一些解析/词法分析技术会很有用.

Rust相关问答推荐

rust 蚀生命周期 行为

是否可以使用Rust宏来构建元组的项?

是否可以在不切换到下一个位置的情况下获得迭代器值:

将一个泛型类型转换为另一个泛型类型

循环访问枚举中的不同集合

Rust编译器似乎被结果类型与anyhow混淆

不同类型泛型的映射

我应该如何表达具有生命周期参数的类型的总排序,同时允许与不同生命周期进行比较?

Rust LinkedList 中的borrow 判断器错误的原因是什么?

Rust 如何将链表推到前面?

当锁被释放时,将锁包装到作用域中是否会发生变化?

在Rust中实现Trie数据 struct 的更好方式

Rust中的位移操作对范围有什么影响?

简单 TCP 服务器的连接由对等重置错误,mio 负载较小

Rust 中的生命周期:borrow 的 mut 数据

在 Bevy 项目中为 TextureAtlas 精灵实施 NearestNeighbor 的正确方法是什么?

rust tokio::spawn 在 mutexguard 之后等待

&str 的编译时拆分是否可能?

仅当满足外部条件时如何添加到 actix web 的路由

如何将 u8 切片复制到 u32 切片中?