public _Typedef(_Symbol aliasOf, int ptr, bool isConst, bool wasForwardDecl = false) { this.aliasOf = aliasOf; this.ptr = (byte)ptr; this.isConst = isConst; this.wasForwardDecl = wasForwardDecl; }
/// <summary> /// Finds symbol by string name. /// </summary> bool _TryFindSymbol(string name, out _Symbol x, bool includingAncestorNamespaces) { fixed(char *n = name) { _Token token = new _Token(n, name.Length); if (_keywords.TryGetValue(token, out x)) { return(true); } for (int i = _nsCurrent; i >= 0; i--) { if (_ns[i].sym.TryGetValue(token, out x)) { return(true); } if (!includingAncestorNamespaces) { break; } } } return(false); }
void _AddKeywords(_Symbol sym, params string[] names) { foreach (string s in names) { _AddKeyword(s, sym); } }
/// <summary> /// Finds symbol of token iTok in _keywords, _ns[_nsCurrent].sym and optionally in _ns[nsCurrent-1 ... 0].sym. /// Error if the token is not an identifier. /// </summary> bool _TryFindSymbol(int iTok, out _Symbol x, bool includingAncestorNamespaces) { _Token token = _tok[iTok]; if (_keywords.TryGetValue(token, out x)) { return(true); } for (int i = _nsCurrent; i >= 0; i--) { if (_ns[i].sym.TryGetValue(token, out x)) { return(true); } if (!includingAncestorNamespaces) { break; } } if (!_TokIsIdent(iTok)) { _Err(iTok, "unexpected"); } return(false); }
/// <summary> /// Adds x to _ns[_nsCurrent].sym. /// Error if already exists, unless it is a forward decl of same type or a typedef of same type. /// </summary> /// <param name="iTokError">Where to show error if need.</param> /// <param name="addToGlobal">Add to _ns[0].sym.</param> void __AddSymbol(_Token name, _Symbol x, int iTokError, bool addToGlobal) { Debug.Assert(_IsCharIdentStart(*name.s)); if (_keywords.ContainsKey(name)) { _Err(iTokError, "name already exists (keyword)"); } int ns = addToGlobal ? 0 : _nsCurrent; //AOutput.Write(name); try { _ns[ns].sym.Add(name, x); } catch (ArgumentException) { _Symbol p = _ns[ns].sym[name]; g1: if (x.GetType() != p.GetType()) { if (((p is _Typedef) && 0 == _Unalias(iTokError, ref p)) || ((x is _Typedef) && 0 == _Unalias(iTokError, ref x))) { goto g1; } _Err(iTokError, "name already exists"); } if (!x.forwardDecl) { if (!(x is _Typedef) && !(x is _Callback)) { _Err(iTokError, "already defined"); } //info: C++ allows multiple identical typedef. We don't check identity, it is quite difficult, assume the header file is without such errors. //info: before adding struct or enum, the caller checks whether it is forward-declaraed. If so, overwrites the forward-declared object and does not call this function, because cannot change object associated with that name because forward-declared object pointer can be used in a typedef. } } }
/// <summary> /// Finds symbol of token iTok in _keywords, _ns[_nsCurrent].sym and optionally in _ns[nsCurrent-1 ... 0].sym. /// Error if not found or not a type (struct, enum etc) or the token is not an identifier. /// </summary> _Symbol _FindType(int iTok, bool includingAncestorNamespaces) { _Symbol x = _FindSymbol(iTok, includingAncestorNamespaces); if (x is _Keyword) { _Err(iTok, "unexpected"); } return(x); }
char *_km; //curent keyword void _AddKeyword(string name, _Symbol sym) { char *n = _km; for (int i = 0; i < name.Length; i++) { *_km++ = name[i]; } _keywords.Add(new _Token(n, (int)(_km - n)), sym); *_km++ = '\0'; }
/// <summary> /// Finds symbol of token iTok everywhere. /// Error if not found or not a keyword or the token is not an identifier. /// </summary> /// <param name="kwType">If not _KeywordT.Any, error if the keyword is not of this type.</param> _Keyword _FindKeyword(int iTok, _KeywordT kwType = _KeywordT.Any) { _Symbol x = _FindSymbol(iTok, true); var k = x as _Keyword; if (k == null) { _Err(iTok, "unexpected"); } if (kwType != _KeywordT.Any && k.kwType != kwType) { _Err(iTok, "unexpected"); } return(k); }
/// <summary> /// If x is _Typedef, replaces it with its deepest used type. /// Error if x is not a type (is _Keyword). /// Returns pointer level. /// </summary> /// <param name="iTok">Used only for error place.</param> int _Unalias(int iTok, ref _Symbol x) { int ptr = 0; var t = x as _Typedef; if (t != null) { x = t.aliasOf; ptr = t.ptr; } else if (x is _Keyword) { _Err(iTok, "unexpected"); } return(ptr); }
/// <summary> /// This overload has isConst parameter. If x is const _Typedef sets the isConst variable = true, else isConst unchanged. /// </summary> int _Unalias(int iTok, ref _Symbol x, ref bool isConst) { int ptr = 0; var t = x as _Typedef; if (t != null) { x = t.aliasOf; ptr = t.ptr; if (t.isConst) { isConst = true; } } else if (x is _Keyword) { _Err(iTok, "unexpected"); } return(ptr); }
public static Expression Set(SExpr sexp, _Symbol variable, Expression value) { return new _Set (sexp, variable, value); }
public _Set(SExpr sexp, _Symbol variable, Expression value) : base(sexp) { Variable = variable; Value = value; }
/// <summary> /// Converts type name/pointer to C# type name. /// The return value is type name, possibly with * or []. If parameter, also can have ref/out/in and [In]/[Out]. /// </summary> /// <param name="t">The type.</param> /// <param name="ptr">Pointer level. The function may adjust it depending on typedef pointer level etc.</param> /// <param name="isConst">Is const.</param> /// <param name="iTokTypename">Type name token index. Can be 0 if don't need to unalias etc; then just adds pointer/ref if need.</param> /// <param name="context">Depending on it char* will be converted to "string" etc.</param> /// <param name="attributes">Receives null or MarshalAs attribute.</param> /// <param name="iSAL">SAL token index, or 0 if no SAL.</param> string _ConvertTypeName(_Symbol t, ref int ptr, bool isConst, int iTokTypename, _TypeContext context, out string attributes, int iSAL = 0) { attributes = null; string name, marshalAs = null; bool isLangType = false, isParameter = false, isCOM = false, isBlittable = false, isRawPtr = false; switch (context) { case _TypeContext.Parameter: case _TypeContext.DelegateParameter: isParameter = true; break; case _TypeContext.ComParameter: isParameter = true; isCOM = true; break; case _TypeContext.ComReturn: isCOM = true; break; } bool _In_ = false, _Out_ = false, _Inout_ = false; if (iSAL > 0) { //AOutput.Write(_tok[iSAL]); if (_TokStarts(iSAL, "_In_")) { _In_ = true; } else if (_TokStarts(iSAL, "_Out")) { _Out_ = true; } else if (_TokStarts(iSAL, "_Inout_")) { _Inout_ = true; } else { _Err(iSAL, "unknown SAL"); } } if (iTokTypename != 0) { ptr += _Unalias(iTokTypename, ref t, ref isConst); name = t.csTypename; var c = t as _CppType; if (c != null) { isLangType = true; isBlittable = true; switch (name) { case "char": isBlittable = false; if (ptr == 1) //not 'if(ptr != 0)', because cannot be 'ref string' { ptr = 0; bool isBSTR = _TokIs(iTokTypename, "BSTR"); switch (context) { case _TypeContext.Member: if (isConst || isBSTR) { name = "string"; if (isBSTR) { marshalAs = "BStr"; } } else { //string dangerous, because if the callee changes member pointer, .NET tries to free the new string with CoTaskMemFree. ptr = 1; //AOutput.Write(_DebugGetLine(iTokTypename)); isRawPtr = true; } break; case _TypeContext.Return: case _TypeContext.ComReturn: ptr = 1; //if string, .NET tries to free the return value isRawPtr = true; break; case _TypeContext.DelegateParameter: ptr = 1; //because some are "LPSTR or WORD". Rarely used. isRawPtr = true; break; case _TypeContext.Parameter: case _TypeContext.ComParameter: Debug.Assert(!(isConst && (_Out_ || _Inout_))); if (isConst || _In_ || isBSTR) { name = "string"; if (isCOM) { //if(!isBSTR) AOutput.Write(_tok[iTokTypename]); if (!isBSTR) { marshalAs = "LPWStr"; } } else { if (isBSTR) { marshalAs = "BStr"; } } } else { ptr = 1; isRawPtr = true; //Could be StringBuilder, but the Au library does not use it, it is slow. //Or [Out] char[]. The Au library uses it with Util.AMemoryArray.Char_. } break; } } else if (ptr > 1) { isRawPtr = true; isConst = false; } break; case "int": if (_TokIs(iTokTypename, "BOOL")) { if (ptr == 0 || (ptr == 1 && isParameter)) { name = "bool"; if (isCOM) { marshalAs = "Bool"; } isBlittable = false; } } break; case "bool": marshalAs = "U1"; isBlittable = false; break; case "void": case "byte": case "sbyte": if (ptr > 0) { isRawPtr = true; } break; case "double": if (_TokIs(iTokTypename, "DATE")) { if (ptr == 0 || (ptr == 1 && isParameter)) { name = "DateTime"; isBlittable = false; } } break; } if (isRawPtr) { isBlittable = true; } } } else { name = t.csTypename; } if (!isLangType) { var ts = t as _Struct; if (ts != null) { if (ts.isInterface) { //OutList(ptr, ts.csTypename); if (ptr == 0) { _Err(iTokTypename, "unexpected"); } ptr--; switch (name) { case "IUnknown": marshalAs = name; name = "Object"; break; //case "IDispatch": //not sure should this be used, because we don't convert SDK interfaces to C# IDispatch interfaces // marshalAs = name; // name = "Object"; // break; } } else if (!ts.isClass) { switch (name) { case "AWnd": case "LPARAM": isBlittable = true; break; case "GUID": name = "Guid"; break; case "DECIMAL": name = "decimal"; break; case "VARIANT": if (context == _TypeContext.ComParameter) { name = "object"; } break; //case "SAFEARRAY": //in SDK used only with SafeArrayX functions, with several other not-important functions and as [PROP]VARIANT members //AOutput.Write(ptr); //break; case "ITEMIDLIST": if (ptr > 0) { ptr--; name = "IntPtr"; isBlittable = true; } //else _Err(iTokTypename, "example"); //0 in SDK break; case "POINTL": name = "POINT"; break; case "RECTL": name = "RECT"; break; } } } else if (t is _Enum) { isBlittable = true; } } if (ptr > 0) { __ctn.Clear(); bool isArray = false; if (!isRawPtr && isParameter) { string sal = null; if (iSAL > 0) { sal = _TokToString(iSAL); } if (iSAL > 0 && ptr == 1) //if ptr>1, can be TYPE[]* or TYPE*[] { if (_In_ && (sal.Contains("_reads_") || sal.Contains("count"))) { //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename)); isArray = true; __ctn.Append("[In] "); } if (_Inout_ && (sal.Contains("_updates_") || sal.Contains("count"))) { //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename)); isArray = true; __ctn.Append("[In,Out] "); } if (_Out_ && (sal.Contains("_writes_") || sal.Contains("count"))) { //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename)); isArray = true; __ctn.Append("[Out] "); } } if (_Inout_) { isConst = false; } if (isArray) { ptr--; } else { ptr--; if (_Out_) { __ctn.Append("out "); } else if (_In_ || isConst) { if (isBlittable) { if (isConst && ptr == 0 && name != "IntPtr") { //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename)); isArray = true; //usually array, because there is no sense for eg 'const int* param', unless it is a 64-bit value (SDK usually then uses LARGE_INTEGER etc, not __int64). Those with just _In_ usually are not arrays, because for arrays are used _In_reads_ etc. } else { __ctn.Append("in "); //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename)); } } else { if (isConst) { __ctn.Append("in "); //prevents copying non-blittable types back to the caller when don't need } else { //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename)); //__ctn.Append("in "); //no, because there are many errors in SDK where inout parameters have _In_ __ctn.Append("ref "); } } } else { __ctn.Append("ref "); } } if (isArray) { bool useMarshalAsSubtype = false; if (isCOM) { //by default marshals as SAFEARRAY if (marshalAs == null) { marshalAs = "LPArray"; } else { useMarshalAsSubtype = true; } } else if (context == _TypeContext.DelegateParameter) { isArray = false; ptr++; __ctn.Clear(); //maybe can be array, not tested. Never mind, in SDK only 4 rarely used. //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename)); } else if (marshalAs != null) { useMarshalAsSubtype = true; } if (useMarshalAsSubtype) { marshalAs = "LPArray, ArraySubType = UnmanagedType." + marshalAs; } } } //if(isParameter) __ctn.Append(name); if (ptr > 0) { __ctn.Append('*', ptr); } if (isArray) { __ctn.Append("[]"); } name = __ctn.ToString(); } if (marshalAs != null) { __ctn.Clear(); string ret = null; if (context == _TypeContext.Return || context == _TypeContext.ComReturn) { ret = "return: "; } attributes = $"[{ret}MarshalAs(UnmanagedType.{marshalAs})]"; } return(name); }
void _Statement() { //try { g0: _Symbol x = _FindSymbol(_i, true); var k = x as _Keyword; if (k != null) { if (k.cannotStartStatement) { _Err(_i, "unexpected"); } if (k.kwType == _KeywordT.TypeDecl) { //is forward decl like 'struct X* Func(...);'? if (!_TokIsChar(_i, 't') && _TokIsChar(_i + 2, '*', '&')) { _InlineForwardDeclaration(); goto g0; } var ftd = new _FINDTYPEDATA(); //just for ref parameter _DeclareType(ref ftd, true); } else if (k.kwType == _KeywordT.IgnoreFuncEtc) { _SkipStatement(); return; } else if (_TokIs(_i, "extern")) { if (_TokIsChar(_i + 1, '\"')) //extern "C" { _i++; if (_TokIsChar(_i + 1, '{')) { _i++; } return; } else //extern T X { if (_TokIs(++_i, "const")) { _i++; } if (!_ExternConst()) { _SkipStatement(); } } } else if (_TokIs(_i, "const")) { _i++; if (!_ExternConst(true)) { _SkipStatement(); } } else { //can be: //namespace _Err(_i, "unexpected"); //TODO } if (!_TokIsChar(_i, ';')) { _Err(_i, "unexpected"); } } else //a type { _DeclareFunction(); } //} //catch(ConverterException e) { // //AOutput.Write(e); // AWnd.FindFast(null, "QM_Editor").SendS(Api.WM_SETTEXT, 1, $"M \"api_converter_error\" A(||) {e.Message}||{_cppFile}||{e.Offset}"); // if(ADialog.Show("Error. Skip statement and continue?", e.Message, "Yes|No").ButtonName != "Yes") throw e as Exception; // _SkipStatement(); // } }
/// <summary> /// Adds x to _ns[_nsCurrent].sym. /// Error if already exists, unless it is a forward decl of same type or a typedef of same type. /// </summary> /// <param name="iTokError">Where to show error if need.</param> /// <param name="addToGlobal">Add to _ns[0].sym.</param> void _AddSymbol(string name, _Symbol x, int iTokError, bool addToGlobal = false) { //AOutput.Write(name); __AddSymbol(_TokenFromString(name), x, iTokError, addToGlobal); }
/// <summary> /// Adds x to _ns[_nsCurrent].sym. /// Error if already exists, unless it is a forward decl of same type or a typedef of same type. /// </summary> /// <param name="iTokName">Token index of symbol name.</param> /// <param name="addToGlobal">Add to _ns[0].sym.</param> void _AddSymbol(int iTokName, _Symbol x, bool addToGlobal = false) { __AddSymbol(_tok[iTokName], x, iTokName, addToGlobal); }