github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/pogosh/arithmetic.go (about) 1 // Copyright 2020 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package pogosh 6 7 import ( 8 "fmt" 9 "math/big" 10 ) 11 12 // After variable substitution has occured, this 13 // evaluates the arithmetic expression. 14 15 // These rules come from ISO C standard, section 6.5 Expression and section 16 // 6.4.4.1 Integer Constants. 17 // LL(3) grammar 18 19 // Params: 20 // map[string]Variable 21 // Returns: 22 // big.Int: value 23 // map[string]big.Int: assignments 24 // Panics: on parse error 25 26 // Arithmetic computes value in $((...)) expression. 27 // TODO: why public? 28 type Arithmetic struct { 29 getVar func(string) *big.Int 30 setVar func(string, *big.Int) 31 32 // Initial string 33 input string 34 35 // Remaining unparsed string 36 rem string 37 } 38 39 // if x == 0, 0 40 // otherwise, 1 41 func bigBool(x *big.Int) *big.Int { 42 if x.BitLen() == 0 { 43 return big.NewInt(0) 44 } 45 return big.NewInt(1) 46 } 47 48 func asBig(b bool) *big.Int { 49 if b { 50 return big.NewInt(1) 51 } 52 return big.NewInt(0) 53 } 54 55 // Wrapper which should be used outside this file. 56 func (a *Arithmetic) evalExpression() *big.Int { 57 // TODO: this might not be standard and might be inefficient 58 // Augment for LL(3) 59 a.rem = a.input + "\000\000\000" 60 val := a.evalAssignmentExpression() 61 a.evalSpaces() 62 if a.rem != "\000\000\000" { 63 panic("Expected EOF at " + a.rem) 64 } 65 return val 66 } 67 68 func (a *Arithmetic) evalSpaces() { 69 for a.rem[0] == ' ' || a.rem[0] == '\t' || a.rem[0] == '\n' { // TODO: more space characters 70 a.rem = a.rem[1:] 71 } 72 } 73 74 // [_0-9a-zA-Z] 75 func isIdentifierChar(char byte) bool { 76 return char == '_' || ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || ('0' <= char && char <= '9') 77 } 78 79 func isDecimal(char byte) bool { 80 return '0' <= char && char <= '9' 81 } 82 83 func isHex(char byte) bool { 84 return ('0' <= char && char <= '9') || ('a' <= char && char <= 'f') || ('A' <= char && char <= 'F') 85 } 86 87 func isOctal(char byte) bool { 88 return ('0' <= char && char <= '7') 89 } 90 91 // Identifier ::= [_a-zA-Z][_0-9a-zA-Z]* 92 func (a *Arithmetic) evalIdentifier() *big.Int { 93 // This does not check the first character is not numeric because it has 94 // already been done as part of the callee's FIRST set. 95 i := 0 96 for isIdentifierChar(a.rem[i]) { 97 i++ 98 } 99 100 identifier := a.rem[:i] 101 a.rem = a.rem[i:] 102 return a.getVar(identifier) 103 } 104 105 // Constant ::= DecimalConstant | OctalConstant | HexadecimalConstant 106 // DecimalConstant ::= [1-9][0-9]* 107 // OctalConstant ::= 0[0-9]* 108 // HexadecimalConstant ::= 0x[0-9]* | 0X[0-9]* 109 func (a *Arithmetic) evalConstant() *big.Int { 110 // Get length of constant. 111 i := 0 112 if a.rem[i] == '0' { 113 i++ 114 if a.rem[i] == 'x' || a.rem[i] == 'X' { 115 i++ 116 for isHex(a.rem[i]) { 117 i++ 118 } 119 } else { 120 for isOctal(a.rem[i]) { 121 i++ 122 } 123 } 124 } else { 125 for isDecimal(a.rem[i]) { 126 i++ 127 } 128 } 129 130 var val big.Int 131 _, ok := val.SetString(a.rem[:i], 0) 132 if !ok { 133 panic("Not a valid constant") 134 } 135 a.rem = a.rem[i:] 136 return &val 137 } 138 139 // PrimaryExpression ::= Identifier | Constant | '(' AssignmentExpression ')' 140 func (a *Arithmetic) evalPrimaryExpression() *big.Int { 141 a.evalSpaces() 142 char := a.rem[0] 143 switch { 144 case '0' <= char && char <= '9': 145 return a.evalConstant() 146 case isIdentifierChar(char): 147 return a.evalIdentifier() 148 case char == '(': 149 a.rem = a.rem[1:] 150 val := a.evalAssignmentExpression() 151 a.evalSpaces() 152 if a.rem[0] != ')' { 153 panic("No matching closing parenthesis") 154 } 155 a.rem = a.rem[1:] 156 return val 157 default: 158 panic(fmt.Sprintf("Expected identifier or constant at %c", char)) 159 } 160 } 161 162 // UnaryExpression ::= PrimaryExpression 163 // UnaryExpression ::= UnaryOperator UnaryExpression 164 // UnaryOperator ::= '+' | '-' | '~' | '!' 165 func (a *Arithmetic) evalUnaryExpression() *big.Int { 166 val := big.NewInt(0) 167 a.evalSpaces() 168 switch a.rem[0] { 169 case '+': 170 a.rem = a.rem[1:] 171 val = a.evalUnaryExpression() 172 case '-': 173 a.rem = a.rem[1:] 174 val.Neg(a.evalUnaryExpression()) 175 case '~': 176 a.rem = a.rem[1:] 177 val.Not(a.evalUnaryExpression()) 178 case '!': 179 a.rem = a.rem[1:] 180 val.Xor(big.NewInt(1), bigBool(a.evalUnaryExpression())) 181 default: 182 val = a.evalPrimaryExpression() 183 } 184 return val 185 } 186 187 // MultiplicativeExpression ::= UnaryExpression MultiplicativeExpression2 188 // MultiplicativeExpression2 ::= MultiplicativeOperator MultiplicativeExpression | 189 // MultiplicativeOperator ::= '*' | '/' | '%' 190 func (a *Arithmetic) evalMultiplicativeExpression() *big.Int { 191 val := a.evalUnaryExpression() 192 for { 193 a.evalSpaces() 194 switch a.rem[0] { 195 case '*': 196 a.rem = a.rem[1:] 197 val.Mul(val, a.evalUnaryExpression()) 198 case '/': 199 a.rem = a.rem[1:] 200 val.Div(val, a.evalUnaryExpression()) 201 case '%': 202 a.rem = a.rem[1:] 203 val.Mod(val, a.evalUnaryExpression()) 204 default: 205 return val 206 } 207 } 208 } 209 210 // AdditiveExpression ::= MultiplicativeExpression AdditiveExpression2 211 // AdditiveExpression2 ::= AdditiveOperator AdditiveExpression | 212 // AdditiveOperator ::= '+' | '-' 213 func (a *Arithmetic) evalAdditiveExpression() *big.Int { 214 val := a.evalMultiplicativeExpression() 215 for { 216 a.evalSpaces() 217 switch a.rem[0] { 218 case '+': 219 a.rem = a.rem[1:] 220 val.Add(val, a.evalMultiplicativeExpression()) 221 case '-': 222 a.rem = a.rem[1:] 223 val.Sub(val, a.evalMultiplicativeExpression()) 224 default: 225 return val 226 } 227 } 228 } 229 230 // ShiftExpression ::= AdditiveExpression ShiftExpression2 231 // ShiftExpression2 ::= ShiftOperator ShiftExpression | 232 // ShiftOperator ::= '<<' | '>>' 233 func (a *Arithmetic) evalShiftExpression() *big.Int { 234 val := a.evalAdditiveExpression() 235 for { 236 a.evalSpaces() 237 switch a.rem[:2] { 238 case "<<": 239 a.rem = a.rem[2:] 240 // TODO: might be undefined if > UINT64_MAX 241 val.Lsh(val, uint(a.evalAdditiveExpression().Uint64())) 242 case ">>": 243 a.rem = a.rem[2:] 244 // TODO: might be undefined if > UINT64_MAX 245 val.Rsh(val, uint(a.evalAdditiveExpression().Uint64())) 246 default: 247 return val 248 } 249 } 250 } 251 252 // RelationalExpression ::= ShiftExpression RelationalExpression2 253 // RelationalExpression2 ::= RelationalOperator RelationalExpression | 254 // RelationalOperator ::= '<' | '>' | '<=' | '>=' 255 func (a *Arithmetic) evalRelationalExpression() *big.Int { 256 val := a.evalShiftExpression() 257 for { 258 a.evalSpaces() 259 switch { 260 case a.rem[:2] == "<=": 261 a.rem = a.rem[2:] 262 val = asBig(val.Cmp(a.evalShiftExpression()) <= 0) 263 case a.rem[:2] == ">=": 264 a.rem = a.rem[2:] 265 val = asBig(val.Cmp(a.evalShiftExpression()) >= 0) 266 case a.rem[0] == '<' && a.rem[1] != '<': 267 a.rem = a.rem[2:] 268 val = asBig(val.Cmp(a.evalShiftExpression()) < 0) 269 case a.rem[0] == '>' && a.rem[1] != '>': 270 a.rem = a.rem[2:] 271 val = asBig(val.Cmp(a.evalShiftExpression()) > 0) 272 default: 273 return val 274 } 275 } 276 } 277 278 // EqualityExpression ::= RelationalExpression EqualityExpression2 279 // EqualityExpression2 ::= EqualityOperator EqualityExpression 280 // EqualityOperator ::= '==' | '!=' 281 func (a *Arithmetic) evalEqualityExpression() *big.Int { 282 val := a.evalRelationalExpression() 283 for { 284 a.evalSpaces() 285 switch a.rem[:2] { 286 case "==": 287 a.rem = a.rem[2:] 288 val = asBig(val.Cmp(a.evalRelationalExpression()) == 0) 289 case "!=": 290 a.rem = a.rem[2:] 291 val = asBig(val.Cmp(a.evalRelationalExpression()) != 0) 292 default: 293 return val 294 } 295 } 296 } 297 298 // ANDExpression ::= EqualityExpression AndExpression2 299 // ANDExpression2 ::= '&' ANDExpression | 300 func (a *Arithmetic) evalANDExpression() *big.Int { 301 val := a.evalEqualityExpression() 302 for { 303 a.evalSpaces() 304 switch { 305 case a.rem[0] == '&' && a.rem[1] != '&': 306 a.rem = a.rem[2:] 307 val.And(val, bigBool(a.evalEqualityExpression())) 308 default: 309 return val 310 } 311 } 312 } 313 314 // ExclusiveORExpression ::= ANDExpression ExclusiveORExpression2 315 // ExclusiveORExpression2 ::= '^' ExclusiveORExpression | 316 func (a *Arithmetic) evalExclusiveORExpression() *big.Int { 317 val := a.evalANDExpression() 318 for { 319 a.evalSpaces() 320 switch a.rem[0] { 321 case '^': 322 a.rem = a.rem[1:] 323 val.Xor(val, bigBool(a.evalANDExpression())) 324 default: 325 return val 326 } 327 } 328 } 329 330 // InclusiveORExpression ::= ExclusiveORExpression InclusiveORExpression2 331 // InclusiveORExpression2 ::= '|' InclusiveORExpression | 332 func (a *Arithmetic) evalInclusiveORExpression() *big.Int { 333 val := a.evalExclusiveORExpression() 334 for { 335 a.evalSpaces() 336 switch { 337 case a.rem[0] == '|' && a.rem[1] != '|': 338 a.rem = a.rem[2:] 339 val.Or(val, bigBool(a.evalExclusiveORExpression())) 340 default: 341 return val 342 } 343 } 344 } 345 346 // LogicalANDExpression ::= InclusiveORExpression LogicalANDExpression2 347 // LogicalANDExpression2 ::= '&&' InclusiveORExpression | 348 func (a *Arithmetic) evalLogicalANDExpression() *big.Int { 349 val := a.evalInclusiveORExpression() 350 for { 351 a.evalSpaces() 352 switch a.rem[:2] { 353 case "&&": 354 a.rem = a.rem[2:] 355 val.And(bigBool(val), bigBool(a.evalInclusiveORExpression())) 356 default: 357 return val 358 } 359 } 360 } 361 362 // LogicalORExpression ::= LogicalANDExpression LogicalORExpression2 363 // LogicalORExpression2 ::= '||' LogicalORExpression | 364 func (a *Arithmetic) evalLogicalORExpression() *big.Int { 365 val := a.evalLogicalANDExpression() 366 for { 367 a.evalSpaces() 368 switch a.rem[:2] { 369 case "||": 370 a.rem = a.rem[2:] 371 val.Or(bigBool(val), bigBool(a.evalLogicalANDExpression())) 372 default: 373 return val 374 } 375 } 376 } 377 378 // ConditionalExpression ::= LogicalORExpression ConditionalExpression2 379 // ConditionalExpression2 ::= '?' AssignmentExpression ':' ConditionalExpression | 380 func (a *Arithmetic) evalConditionalExpression() *big.Int { 381 val := a.evalLogicalORExpression() 382 383 a.evalSpaces() 384 if a.rem[0] != '?' { 385 return val 386 } 387 a.rem = a.rem[1:] 388 trueVal := a.evalAssignmentExpression() 389 390 if a.rem[0] != ':' { 391 panic("Bad conditional expression") 392 } 393 a.rem = a.rem[1:] 394 falseVal := a.evalConditionalExpression() 395 396 if val.BitLen() == 0 { 397 return falseVal 398 } 399 return trueVal 400 } 401 402 // AssignmentExpression ::= ConditionalExpression 403 // AssignmentExpression ::= Identifier AssignmentOperator AssignmentExpression 404 // AssignmentOperator ::= '=' | '*=' | '/=' | '%=' | '+=' | '-=' | '<<=' 405 // | '>>=' | '&=' | '^=' | '|=' 406 func (a *Arithmetic) evalAssignmentExpression() *big.Int { 407 val := a.evalConditionalExpression() 408 // TODO: assignment 409 // TODO: some other follow sets need to be updated 410 return val 411 }