在下面的代码中,executeProg函数正在执行程序指令列表。它使用“ PUSH ax,POP bx ..etc”执行程序。
//Execute a program as a list of operations. Note how pc is incremented
//so any jump instruction must be written carefully.
let mutable executeProg = fun (program:operation list) ->
pc <- 0
fault <- false
while not(fault) && pc<program.Length do
let instruction = program.[pc];
execute instruction
pc <- pc+1
// end of while by indentation
if not(fault) then printfn "top of stack holds value %d" (RAM.[sp-1]);
我想做的是:修改executeProg使其执行以下操作:
push ax
pop bx --> replace with single instruction mov ax bx
push ax
pop ax --> eliminate altogether
mov ax bx
mov bx ax --> mov ax bx
我的问题是,如何在不更改原始模型的情况下实现新的executeProg模态?我的代码如下:
let base_executeProg = executeProg
executeProg <- fun program (program:operation list) ->
let rec matchingFun = fun newProgram (program:operation list ) ->
let mutable newProgram = newProgram
match program with
| (PUSH(Reg(a)):: POP(Reg(b)) :: r) ->
newProgram <- newProgram @ [MOV(Reg(a),Reg(b))]
(matchingFun (newProgram r))
newProgram
| (PUSH(Reg(a)):: POP(Reg(a))::r) ->
(matchingFun (newProgram r))
newProgram
| (MOV(Reg(a),Reg(b)):: MOV(Reg(b),Reg(a)):: r) ->
newProgram <- newProgram @ [MOV(Reg(a),Reg(b))]
(matchingFun (newProgram r))
newProgram
| (a::r) ->
newProgram <- newProgram @ [a]
matchingFun(newProgram,r)
newProgram
| [] -> newProgram
我是F#语言的新手,我想知道我的语法是否正确。感谢您的帮助谢谢。
我认为您不需要具有可变功能。也许您可以将设计更改为使用不变的,可组合的结构,从而使您可以向解决方案中添加新功能。
我有点打问题了,这就是我得到的。
声明将在程序中使用的类型:
type Register =
| AX
| BX
type Operand =
| Register of Register
| Int of int
type Command =
| MOV of Register * Operand
| PUSH of Operand
| POP of Operand
type FnBinaryOp = Register -> Operand -> Command
type FnUnaryOp = Operand -> Command
type Program = Command list
//two helper functions to save some typing
let i n = Int n
let r n = Register n
//helper functions to clarify the declaration syntax
let mov:FnBinaryOp =
fun reg op -> MOV (reg, op)
let push: FnUnaryOp = fun op -> PUSH (op)
let pop: FnUnaryOp = fun op -> POP (op)
实施优化方法-它返回修改后的指令列表。这是纠正代码效率低下的地方。
///optimize the program - remove cancelling stack commands, simplify MOV commands
let optimize (program:Program) =
let rec recOptimize stack prog =
match prog with
| PUSH (Register r1)::POP (Register r2)::xs when r1 = r2 -> //push ax; pop ax => nop
xs |> recOptimize stack
| PUSH (Register r1)::POP (Register r2)::xs when r1 <> r2 -> //push ax; pop bx => move ax bx
xs |> recOptimize (MOV(r1, Register(r2))::stack)
| PUSH (Int i1)::POP (Int i2)::xs when i1 = i2 -> //push 3; pop 3 => nop
xs |> recOptimize stack
| ((MOV (r1, Register r2 )) as op1)::((MOV (r3, Register r4 )) as op2)::xs when r1 = r4 && r2 = r3 -> //move ax bx; move bx ax => move ax bx
xs |> recOptimize (op1::stack)
| ((MOV (r1, Register r2 )) as op1)::((MOV (r3, Register r4 )) as op2)::xs when r1 = r3 && r2 = r4 -> //move ax bx; move ax bx => move ax bx
xs |> recOptimize (op1::stack)
| op::xs -> //all other cases - pass through
xs |> recOptimize (op::stack)
| [] -> stack
program
|> recOptimize []
实现程序的实际执行(此处未实现)
let runProgram (program:Program) =
let rec run stack prog =
[]
program |> run []
这是调用此方法的方法:
let program:Program = [
mov AX (r BX)
push (r BX)
pop (r BX)
mov AX (r BX)
]
program
|> optimize
|> runProgram
如果需要在优化步骤中添加新功能,则只需替换复合调用中的optimize元素即可。您可以运行多次遍历的优化,以涵盖某些操作“成对”并且您也要对其进行优化的情况。程序|>优化|>优化|> runProgram
以下是一些测试:
[<Fact>]
let ``push 42; pop 42 => nop`` () =
let program:Program = [
push (i 42)
pop (i 42)
]
let optimized = program |> optimize
//should be reduced to empty list
Assert.Empty(optimized)
[<Fact>]
let ``push ax; pop ax => nop`` () =
let program:Program = [
push (r AX)
pop (r AX)
]
let optimized = program |> optimize
//should be reduced to empty list
Assert.Empty(optimized)
[<Fact>]
let ``push ax; pop bx => move ax bx`` () =
let program:Program = [
push (r AX)
pop (r BX)
]
let optimized = program |> optimize
//should be reduced to a single element list mov ax bx
let expected = MOV( AX, (r BX))
let op = optimized.Head
Assert.Equal(1, optimized.Length)
Assert.Equal(expected, op)
[<Fact>]
let ``move ax bx; move bx ax => move ax bx`` () =
let program:Program = [
mov AX (r BX)
mov BX (r AX)
]
let optimized = program |> optimize
//should be reduced to a single element list mov ax bx
let expected = MOV( AX, (r BX))
let op = optimized.Head
Assert.Equal(1, optimized.Length)
Assert.Equal(expected, op)
[<Fact>]
let ``run optimize on program`` () =
let program:Program = [
mov AX (r BX)
push (r BX)
pop (r BX)
mov AX (r BX)
]
let optimized = program
|> optimize
|> optimize
|> optimize
//should be reduced to a single element list mov ax bx
let expected = MOV( AX, (r BX))
let op = optimized.Head
Assert.Equal(1, optimized.Length)
Assert.Equal(expected, op)