1 #ifndef _Formula_h_ 2 #define _Formula_h_ 3 /* Formula.h 4 * 5 * Copyright (C) 1990-2005,2007,2008,2011-2020 Paul Boersma 6 * 7 * This code is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or (at 10 * your option) any later version. 11 * 12 * This code is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 * See the GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this work. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "Data.h" 22 #include <new> 23 24 #define kFormula_EXPRESSION_TYPE_NUMERIC 0 25 #define kFormula_EXPRESSION_TYPE_STRING 1 26 #define kFormula_EXPRESSION_TYPE_NUMERIC_VECTOR 2 27 #define kFormula_EXPRESSION_TYPE_NUMERIC_MATRIX 3 28 #define kFormula_EXPRESSION_TYPE_NUMERIC_TENSOR3 4 29 #define kFormula_EXPRESSION_TYPE_NUMERIC_TENSOR4 5 30 #define kFormula_EXPRESSION_TYPE_STRING_ARRAY 6 31 #define kFormula_EXPRESSION_TYPE_UNKNOWN 7 32 33 Thing_declare (InterpreterVariable); 34 35 /* 36 A stack element may be 32 bytes large, so with a stack size of 1'000'000 37 we have 32 MB for the stack. A formula instruction may be 16 bytes large, 38 so we have 16 MB for lexical analysis and 16 MB for the parse. 39 */ 40 #define Formula_MAXIMUM_STACK_SIZE 1'000'000 41 42 typedef struct structStackel { 43 #define Stackel_NUMBER 0 44 #define Stackel_STRING 1 45 #define Stackel_NUMERIC_VECTOR 2 46 #define Stackel_NUMERIC_MATRIX 3 47 #define Stackel_NUMERIC_TENSOR3 4 48 #define Stackel_NUMERIC_TENSOR4 5 49 #define Stackel_STRING_ARRAY 6 50 #define Stackel_VARIABLE -1 51 #define Stackel_OBJECT -2 52 int which; // 0 or negative = no clean-up required, positive = requires clean-up 53 bool owned; // relevant only to numeric vector/matrix/tensor3/tensor4/strvec/strmat 54 /* 55 The following member of structStackel can either be a struct or a union. 56 The struct option is the easy option: no special care will have to be taken when assigning to its members. 57 The union option attempts to optimize for space and perhaps speed by putting the variants into a smaller space, 58 but it requires special logic for initialization, deletion, and assignment. 59 The special logic is partly implemented by encapsulating _string as a "private" member. 60 */ 61 #define STACKEL_VARIANTS_ARE_PACKED_IN_A_UNION 1 62 #if STACKEL_VARIANTS_ARE_PACKED_IN_A_UNION 63 union 64 #else 65 struct 66 #endif 67 { 68 double number; 69 autostring32 _string; 70 Daata object; 71 VEC numericVector; 72 MAT numericMatrix; 73 STRVEC stringArray; 74 InterpreterVariable variable; 75 }; structStackelstructStackel76 structStackel () { 77 memset (this, 0, sizeof (structStackel)); // union-safe zeroing of all members of structStackel 78 Melder_assert (our which == Stackel_NUMBER); // check that on this computer, 0 is represented with zero bits only 79 Melder_assert (our number == 0.0); // check that on this computer, 0.0 is represented with zero bits only 80 Melder_assert (! our _string); // check that on this computer, a plain-old-data null pointer is represented with zero bits only 81 Melder_assert (! our object); // check that on this computer, a class null pointer is represented with zero bits only 82 Melder_assert (! our owned); // check that on this computer, false is represented with zero bits only 83 } resetstructStackel84 void reset () { // union-safe destruction: test which variant we have 85 if (our which <= Stackel_NUMBER) 86 return; 87 if (our which == Stackel_STRING) { 88 our _string. reset(); 89 } else if (our which == Stackel_NUMERIC_VECTOR) { 90 if (our owned) { 91 {// scope 92 autoVEC removable; 93 removable. adoptFromAmbiguousOwner (our numericVector); 94 } 95 our numericVector = VEC (); // undangle 96 } 97 } else if (our which == Stackel_NUMERIC_MATRIX) { 98 if (our owned) { 99 {// scope 100 autoMAT removable; 101 removable. adoptFromAmbiguousOwner (our numericMatrix); 102 } 103 our numericMatrix = MAT (); // undangle 104 } 105 } else if (our which == Stackel_STRING_ARRAY) { 106 if (our owned) { 107 {// scope 108 autoSTRVEC removable; 109 removable. adoptFromAmbiguousOwner (our stringArray); 110 } 111 our stringArray = STRVEC (); // undangle 112 } 113 } 114 } ~structStackelstructStackel115 ~structStackel () { // union-safe destruction: test which variant we have 116 our reset(); 117 } 118 structStackel& operator= (structStackel&& other) noexcept { // generalized move assignment 119 if (& other != this) { 120 our reset(); 121 memmove (this, & other, sizeof (structStackel)); // union-safe: even our biggest variant is bit-copied entirely 122 memset (& other, 0, sizeof (structStackel)); // union-safe: even the biggest variant in `other` is erased 123 } 124 return *this; 125 } getStringstructStackel126 conststring32 getString () { 127 return our _string.get(); 128 } moveStringstructStackel129 autostring32 moveString () { 130 return our _string.move(); 131 } setStringstructStackel132 void setString (autostring32 newString) { 133 our reset(); 134 #if STACKEL_VARIANTS_ARE_PACKED_IN_A_UNION 135 ::new (& our _string) autostring32(); // a convoluted and type-unsafe, but portable, way to null those 32 or 64 bits 136 #endif 137 our which = Stackel_STRING; 138 our _string = newString.move(); 139 } 140 conststring32 whichText (); 141 } *Stackel; 142 143 struct Formula_Result { 144 int expressionType; 145 double numericResult; 146 autostring32 stringResult; 147 VEC numericVectorResult; 148 MAT numericMatrixResult; 149 STRVEC stringArrayResult; 150 bool owned; Formula_ResultFormula_Result151 Formula_Result () { 152 our expressionType = kFormula_EXPRESSION_TYPE_NUMERIC; 153 our numericResult = 0.0; 154 our stringResult = autostring32(); 155 our numericVectorResult = VEC (); 156 our numericMatrixResult = MAT (); 157 our stringArrayResult = STRVEC (); 158 our owned = false; 159 } resetFormula_Result160 void reset () { 161 our stringResult. reset(); 162 if (our owned) { 163 {// scope 164 autoVEC removable; 165 removable. adoptFromAmbiguousOwner (our numericVectorResult); 166 } 167 our numericVectorResult = VEC (); // undangle 168 {// scope 169 autoMAT removable; 170 removable. adoptFromAmbiguousOwner (our numericMatrixResult); 171 } 172 our numericMatrixResult = MAT (); // undangle 173 {// scope 174 autoSTRVEC removable; 175 removable. adoptFromAmbiguousOwner (our stringArrayResult); 176 } 177 our stringArrayResult = STRVEC (); // undangle 178 } 179 } ~Formula_ResultFormula_Result180 ~ Formula_Result () { 181 our reset(); 182 } 183 }; 184 185 Thing_declare (Interpreter); 186 187 void Formula_compile (Interpreter interpreter, Daata data, conststring32 expression, int expressionType, bool optimize); 188 189 void Formula_run (integer row, integer col, Formula_Result *result); 190 191 /* End of file Formula.h */ 192 #endif 193