Exemplo n.º 1
0
 public _Typedef(_Symbol aliasOf, int ptr, bool isConst, bool wasForwardDecl = false)
 {
     this.aliasOf        = aliasOf;
     this.ptr            = (byte)ptr;
     this.isConst        = isConst;
     this.wasForwardDecl = wasForwardDecl;
 }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 3
0
 void _AddKeywords(_Symbol sym, params string[] names)
 {
     foreach (string s in names)
     {
         _AddKeyword(s, sym);
     }
 }
Exemplo n.º 4
0
        /// <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);
        }
Exemplo n.º 5
0
        /// <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.
                }
            }
        }
Exemplo n.º 6
0
        /// <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);
        }
Exemplo n.º 7
0
        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';
        }
Exemplo n.º 8
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);
        }
Exemplo n.º 9
0
        /// <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);
        }
Exemplo n.º 10
0
        /// <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);
        }
Exemplo n.º 11
0
 public static Expression Set(SExpr sexp, _Symbol variable, Expression value)
 {
     return new _Set (sexp, variable, value);
 }
Exemplo n.º 12
0
 public _Set(SExpr sexp, _Symbol variable, Expression value)
     : base(sexp)
 {
     Variable = variable;
     Value = value;
 }
Exemplo n.º 13
0
        /// <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);
        }
Exemplo n.º 14
0
        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();
            //         }
        }
Exemplo n.º 15
0
 /// <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);
 }
Exemplo n.º 16
0
 /// <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);
 }