0

Rust で最適化ブレインファック コンパイラを作成しようとしています。現在、トークンはフラットなベクトルに格納されていますが、これは機能しますが、構文ツリーを使用するように変更するのに問題があります:

#[derive(Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop(Vec<Token>),
    Move(i32),
    Add(i32, i32),
    LoadOut(i32, i32),
}
use Token::*;

pub fn parse(code: &str) -> Vec<Token> {
    let mut alltokens = Vec::new();
    let mut tokens = &mut alltokens;
    let mut tokvecs: Vec<&mut Vec<Token>> = Vec::new();
    for i in code.chars() {
        match i {
            '+' => tokens.push(Add(0, 1)),
            '-' => tokens.push(Add(0, -1)),
            '>' => tokens.push(Move(1)),
            '<' => tokens.push(Move(-1)),
            '[' => {
                tokens.push(Loop(Vec::new()));
                tokvecs.push(&mut tokens);
                if let &mut Loop(mut newtokens) = tokens.last_mut().unwrap() {
                    tokens = &mut newtokens;
                }
            },
            ']' => {
                tokens = tokvecs.pop().unwrap();
            },
            ',' => tokens.push(Input),
            '.' => {
                tokens.push(LoadOut(0, 0));
                tokens.push(Output);
            }
            _ => (),
        };
    }

    alltokens
}

私が理解するのに苦労しているのは、[コマンドの処理方法です。コード内の現在の実装は、私が試したいくつかの実装のうちの 1 つですが、すべて失敗しました。Rust の を使用する必要があると思いますが、それがBoxどのように使用されているのかよくわかりません。

コマンドを処理するブランチ[はおそらく完全に間違っていますが、どうすればよいかわかりません。ベクトルを含む (列挙Loop型のバリアント) をベクトルにプッシュします。問題は、そのベクトルの変更可能な借用を取得することです。これは、ステートメントが実行することになっています。TokentokensLoopif let

ブロックnewtokensの最後まで存続しないため、コードはコンパイルに失敗します。if let内部のベクトルへの変更可能な参照を取得してLoop、それに設定tokensすることは可能ですか? そうでない場合、代わりに何ができますか?

4

2 に答える 2

0

再帰関数にすることで、コードが機能するようになりました。

#[derive(Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop(Vec<Token>),
    Move(i32),
    Add(i32, i32),
    LoadOut(i32, i32),
}
use Token::*;

pub fn parse(code: &str) -> Vec<Token> {
    _parse(&mut code.chars())
}

fn _parse(chars: &mut std::str::Chars) -> Vec<Token> {
    let mut tokens = Vec::new();
    while let Some(i) = chars.next() {
        match i {
            '+' => tokens.push(Add(0, 1)),
            '-' => tokens.push(Add(0, -1)),
            '>' => tokens.push(Move(1)),
            '<' => tokens.push(Move(-1)),
            '[' => tokens.push(Loop(_parse(chars))),
            ']' => { break; }
            ',' => tokens.push(Input),
            '.' => {
                tokens.push(LoadOut(0, 0));
                tokens.push(Output);
            }
            _ => (),
        };
    }

    tokens
}

それは機能しているようで、かなりシンプルでエレガントです (再帰を使用しないソリューションを見てみたいと思います)。

于 2016-09-06T22:06:21.727 に答える