我正在使用 Ocamllex 为Brainfuck编写一个词法分析器,为了实现它的循环,我需要更改 lexbuf 的状态,以便它可以返回到流中的先前位置。
Brainfuck 的背景信息(可跳过)
在 Brainfuck 中,循环由一对方括号完成,规则如下:
[
-> 继续并评估下一个令牌]
-> 如果当前单元格的值不为0,则返回匹配[
因此,以下代码的计算结果为 15:
+++ [ > +++++ < - ] > .
上面写着:
- 在第一个单元格中,分配 3(递增 3 次)
- 进入循环,移动到下一个单元格
- 赋值 5(递增 5 倍)
- 移回第一个单元格,并从其值中减去 1
- 点击右方括号,现在当前单元格(第一个)等于 2,因此跳回
[
并再次进入循环- 继续直到第一个单元格等于0,然后退出循环
- 移动到第二个单元格并输出值
.
第二个单元格中的值将增加到 15(以 5 为增量增加 3 次)。
问题:
基本上,我编写了两个函数来处理在文件[
的标题部分中推送和弹出最后一个位置的最后一个位置,即将 lexbuf 的当前位置推送和弹出到命名:brainfuck.mll
push_curr_p
pop_last_p
int list ref
loopstack
{ (* Header *)
let tape = Array.make 100 0
let tape_pos = ref 0
let loopstack = ref []
let push_curr_p (lexbuf: Lexing.lexbuf) =
let p = lexbuf.Lexing.lex_curr_p in
let curr_pos = p.Lexing.pos_cnum in
(* Saving / pushing the position of `[` to loopstack *)
( loopstack := curr_pos :: !loopstack
; lexbuf
)
let pop_last_p (lexbuf: Lx.lexbuf) =
match !loopstack with
| [] -> lexbuf
| hd :: tl ->
(* This is where I attempt to bring lexbuf back *)
( lexbuf.Lexing.lex_curr_p <- { lexbuf.Lexing.lex_curr_p with Lexing.pos_cnum = hd }
; loopstack := tl
; lexbuf
)
}
{ (* Rules *)
rule brainfuck = parse
| '[' { brainfuck (push_curr_p lexbuf) }
| ']' { (* current cell's value must be 0 to exit the loop *)
if tape.(!tape_pos) = 0
then brainfuck lexbuf
(* this needs to bring lexbuf back to the previous `[`
* and proceed with the parsing
*)
else brainfuck (pop_last_p lexbuf)
}
(* ... other rules ... *)
}
其他规则工作得很好,但它似乎忽略了[
and ]
。问题显然在于loopstack
我如何获取和设置lex_curr_p
状态。将不胜感激任何线索。