/// <summary> Makes constant values specified as arithmetic expressions comply with the current /// langauge syntax (adds enum type name qualifiers and type casts when necessary, eliminates /// sizeof() operators when unsupported, etc.) </summary> public static string TranslateConstExpr(TpmConstExpr ce, TpmEnum enclosingEnum = null) { var nameDelimiters = new char[] { ' ', ',', '{', '}', '(', ')', '+', '-', '<', '*', '/', '`' }; string suffix = TargetLang.Java ? ".toInt()" : ""; string expr = ce.Expr; string[] tokens = expr.Split(nameDelimiters); bool sizeofOccurred = false, commentNeeded = false; foreach (string token in tokens) { if (token.Length == 0) { continue; } if (token == "sizeof") { Debug.Assert(!sizeofOccurred); sizeofOccurred = true; continue; } if (Expression.IsNumber(token)) { if (token == "00") { Debug.Assert(expr == token); expr = "0"; } Debug.Assert(!sizeofOccurred); continue; } TpmNamedConstant nc = TpmTypes.LookupConstant(token); if (enclosingEnum != null && nc?.EnclosingEnum == enclosingEnum) { // Members of the enum being processed do not need to be qualified Debug.Assert(token == nc.SpecName); expr = expr.Replace(token, nc.Name + suffix); continue; } if (!TpmTypes.ContainsConstant(token)) { // This must be a type name operand of sizeof() Debug.Assert(sizeofOccurred); sizeofOccurred = false; TpmType t = TpmTypes.Lookup(token); if (t is TpmStruct || TargetLang.IsOneOf(Lang.Java, Lang.JS, Lang.Py)) { string sizeofExpr = "sizeof(" + token + ")"; Debug.Assert(expr.Contains(sizeofExpr)); commentNeeded = TargetLang.Py; string origExpr = TargetLang.Py ? "" : $"/*{sizeofExpr}*/"; expr = expr.Replace(sizeofExpr, $"0x{t.GetSize():X}{origExpr}"); } else if (TargetLang.DotNet) { expr = expr.Replace(token, t.StripTypedefs().Name); } } else { nc = TpmTypes.LookupConstant(token); var translated = nc.QualifiedName + suffix; if (!TargetLang.IsGenerated(nc.EnclosingEnum)) { translated = nc.NumericValue.ToString(); if (!TargetLang.Py) { translated += "/*" + token + "*/"; } else { commentNeeded = true; } } expr = expr.Replace(token, translated); } } // foreach token if (TargetLang.DotNet && expr.Contains("<<")) { // Shift operator in .Net requires right operand of type 'int' and unsigned left one. int curPos = 0; expr = expr.Replace(" << ", "<<"); do { int pos = expr.IndexOf("<<", curPos); if (pos == -1) { break; } curPos = pos + 2 + 6; // Add sizes of "<<" and "(uint)" while (char.IsLetterOrDigit(expr[--pos]) || expr[pos] == '.') { continue; } expr = expr.Insert(pos + 1, "(uint)"); } while (true); expr = expr.Replace("<<", " << (int)"); } if (commentNeeded) { expr += $" # {ce.Expr}"; } return(expr); } // TranslateConstExpr()
/// <remarks> If this method goes into an infinite loop, this usually means that /// the Part 2, or Vendor Specicfic part of the TPM 2.0 spec added a new constant /// value defined not in a table, but rather in a NOTE. In this case this definition /// needs to be manually added into the ImplementationConstants array. </remarks> public static int Eval(string val) { if (IsNumber(val)) { return(Convert.ToInt32(val, val.ToLower().StartsWith("0x") ? 16 : 10)); } if (TpmTypes.ContainsConstant(val)) { return(TpmTypes.LookupConstant(val).NumericValue); } var tokens = Tokenize(val); var ops = new Stack <Operator>(); var values = new Stack <Operand>(); for (int i = 0; i < tokens.Length; ++i) { var tok = tokens[i]; if (tok is Operand) { values.Push((Operand)tok); continue; } var op = (Operator)tok; if (op.Is(OpCode.Sizeof)) { Debug.Assert(tokens.Length > i + 2); string typeName = (tokens[i + 2] as Operand).Value; Debug.Assert(TpmTypes.Contains(typeName)); var e = TpmTypes.Lookup(typeName); // Workaround for _PRIVATE max size values.Push(new Operand(typeName == "_PRIVATE" ? 1024 : e.GetSize())); i += 3; continue; } if (ops.Count == 0 || op.Is(OpCode.LeftParen) || ops.Peek() < op) { Debug.Assert(!op.Is(OpCode.RightParen)); ops.Push(op); continue; } else { do { Operator prevOp = ops.Pop(); if (prevOp.Is(OpCode.LeftParen)) { Debug.Assert(op.Is(OpCode.RightParen)); break; } prevOp.Apply(values); }while (ops.Count > 0 && ops.Peek() >= op); if (!op.Is(OpCode.RightParen)) { ops.Push(op); } } } while (ops.Count > 0) { ops.Pop().Apply(values); } Debug.Assert(values.Count == 1); int res = values.Pop().NumericValue; return(res); }