github.com/cowsed/Parser@v0.0.0-20211216032244-48b10019d380/compile.go (about) 1 package parser 2 3 import ( 4 "math" 5 ) 6 7 //Bytecode is an instruction type for the interpreter 8 type Bytecode int 9 10 //List of Bytecodes 11 const ( 12 AddBytecode = iota //Add two memory locations and save to third memory location 13 SubBytecode //Subtract two memory locations and save to third memory location 14 MulBytecode 15 DivBytecode 16 PowBytecode //Raise first location to power of second location and save it at third 17 CosBytecode //Take the cosine of the first locartion and save it to the second 18 SinBytecode 19 LNBytecode 20 ) 21 22 //MemoryManager keeps track of constants, variables and working memory 23 //Also holds place for instructions 24 type MemoryManager struct { 25 bc []Bytecode 26 constants []float64 27 //Guide for which places to fill with which variables 28 varLocations map[string]int 29 } 30 31 //NewMemoryManager returns a new default memory manager 32 func NewMemoryManager() MemoryManager { 33 return MemoryManager{ 34 constants: []float64{}, 35 varLocations: map[string]int{}, 36 } 37 } 38 39 //AddBytecode adds a bytecode to the instructions 40 func (mm *MemoryManager) AddBytecode(bc []Bytecode) { 41 mm.bc = append(mm.bc, bc...) 42 } 43 44 //AddVariable adds a variable and tracks it to be set at execution time 45 func (mm *MemoryManager) AddVariable(name string) int { 46 //Add Variable to memory and return the index to it 47 48 //If its already here 49 if i, ok := mm.varLocations[name]; ok { 50 return i 51 } 52 //if its new 53 index := mm.GetResultSpace() 54 mm.varLocations[name] = index 55 return index 56 57 } 58 59 //AddConstant adds a constant into the memory 60 func (mm *MemoryManager) AddConstant(v float64) int { 61 //Add Constant to memory and return the index to it 62 i := len(mm.constants) 63 mm.constants = append(mm.constants, v) 64 return i 65 } 66 67 //GetResultSpace returns a location for the next variable or constant to be put in 68 func (mm *MemoryManager) GetResultSpace() int { 69 //Add place in memory to store a result and return the index to it 70 i := len(mm.constants) 71 mm.constants = append(mm.constants, -8008) 72 return i 73 } 74 75 //CompileExpression takes an expression and turns it into bytecode 76 func CompileExpression(e Expression) func(vs map[string]float64) float64 { 77 mm := NewMemoryManager() 78 lastResIndex := e.Compile(&mm) 79 vars := make([]string, len(mm.varLocations)) 80 i := 0 81 for k := range mm.varLocations { 82 vars[i] = k 83 i++ 84 } 85 86 compiledFunc := func(vs map[string]float64) float64 { 87 //Copy over code and constants 88 code := mm.bc 89 consts := mm.constants 90 //save vs to mem bank 91 for _, k := range vars { 92 index := mm.varLocations[k] 93 val := vs[k] 94 consts[index] = val 95 96 } 97 //Execute code 98 for i := 0; i < len(code); { 99 ins := code[i] 100 switch ins { 101 case AddBytecode: 102 Ai := code[i+1] 103 Bi := code[i+2] 104 105 Ri := code[i+3] 106 consts[Ri] = consts[Ai] + consts[Bi] 107 i += 4 108 case SubBytecode: 109 Ai := code[i+1] 110 Bi := code[i+2] 111 112 Ri := code[i+3] 113 consts[Ri] = consts[Ai] - consts[Bi] 114 i += 4 115 case MulBytecode: 116 Ai := code[i+1] 117 Bi := code[i+2] 118 119 Ri := code[i+3] 120 consts[Ri] = consts[Ai] * consts[Bi] 121 i += 4 122 123 case DivBytecode: 124 Ai := code[i+1] 125 Bi := code[i+2] 126 127 Ri := code[i+3] 128 consts[Ri] = consts[Ai] / consts[Bi] 129 i += 4 130 case PowBytecode: 131 Ai := code[i+1] 132 Bi := code[i+2] 133 134 Ri := code[i+3] 135 consts[Ri] = math.Pow(consts[Ai], consts[Bi]) 136 i += 4 137 case CosBytecode: 138 Ai := code[i+1] 139 140 Ri := code[i+2] 141 consts[Ri] = math.Cos(consts[Ai]) 142 i += 3 143 144 case SinBytecode: 145 Ai := code[i+1] 146 Ri := code[i+2] 147 consts[Ri] = math.Sin(consts[Ai]) 148 i += 3 149 case LNBytecode: 150 Ai := code[i+1] 151 Ri := code[i+2] 152 consts[Ri] = math.Log(consts[Ai]) 153 i += 3 154 155 default: 156 //This should really never happen but just go to next instruction 157 i++ 158 } 159 160 } 161 return consts[lastResIndex] 162 } 163 return compiledFunc 164 }