我正在用Ocamllex爲Brainfuck編寫一個詞法分析器,爲了實現其循環,我需要更改lexbuf的狀態,以便它可以返回到流中的前一個位置。上Brainfuck(可跳過)更改Lexing.lexbuf的狀態
背景信息
在Brainfuck,環路是通過一對方括號與 完成了以下的規則:
[
- >繼續進行,並評估下一個標記]
- >如果當前單元格的值不是0,則返回匹配的[
因此,下面的代碼的計算結果爲15:
+++ [ > +++++ < - ] > .
記載:
- 在第一小區,分配3(增量3次)
- 輸入迴路,移動到下一個單元
- 指定5(增量5次)
- 回到第一個ce LL,並從它的值中減去1
- 擊中右方括號,現在當前小區(第一)是等於2,從而跳回到
[
並繼續進入循環再次- 保持下去,直到所述第一小區是等於0,則退出循環
- 移動到所述第二小區和輸出的值與
.
在第二單元中的值將被遞增到15 (由5 3次遞增)。
問題:
基本上,我寫了兩個函數來照顧壓入和彈出的brainfuck.mll
文件的開頭部分的最後[
的最後一個位置即push_curr_p
和pop_last_p
其push和pop該lexbuf的當前位置到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 ... *)
}
其它的規則,工作得很好,b似乎忽略[
和]
。問題顯然在loopstack
以及我如何獲得並設置lex_curr_p
狀態。將不勝感激任何線索。
把解釋器放在詞法分析器裏面有什麼好處? – sepp2k
@ sepp2k只是爲了學習ocamllex。對於Brainfuck,可以用簡單的Ocaml編寫遞歸解析器(我已經完成)。 – PieOhPah
我的意思並不是要聽起來(或者是)相反,但是如果你想學習ocamllex,將它用於其預期目的不會更有意義(也就是說,用它來編寫詞法分析器,而不是整個解釋器)?我甚至不確定你想要做什麼(即在詞法分析器中循環)甚至是可能的,如果可能的話,你會從中學到什麼,在實際項目中使用ocamllex會有用嗎? – sepp2k