diff --git a/Source/Converter/ESCLParser.cs b/Source/Converter/ESCLParser.cs index 395d391a..c1ff85a0 100644 --- a/Source/Converter/ESCLParser.cs +++ b/Source/Converter/ESCLParser.cs @@ -194,19 +194,10 @@ namespace CHeaderToXML string funcname = null; GetFunctionNameAndType(words, out funcname, out rettype); - var paramaters_string = Regex.Match(line, @"\(.*\)").Captures[0].Value.TrimStart('(').TrimEnd(')'); - - // This regex matches function parameters. - // The first part matches function pointers in the following format: - // '[return type] (*[function pointer name])([parameter list]) [parameter name] - // where [parameter name] may or may not be in comments. - // The second part (after the '|') matches parameters of the following formats: - // '[parameter type] [parameter name]', '[parameter type] [pointer] [parameter name]', 'const [parameter type][pointer] [parameter name]' - // where [parameter name] may be inside comments (/* ... */) and [pointer] is '', '*', '**', etc. - var get_param = new Regex(@"(\w+\s\(\*\w+\)\s*\(.*\)\s*(/\*.*?\*/|\w+)? | (const\s)?(\w+\s*)+\**\s*(/\*.*?\*/|\w+(\[.*?\])?)),?", RegexOptions.IgnorePatternWhitespace); + var parameters_string = Regex.Match(line, @"\(.*\)").Captures[0].Value.TrimStart('(').TrimEnd(')'); var parameters = - (from item in get_param.Matches(paramaters_string).OfType() + (from item in get_param.Matches(parameters_string).OfType() select item.Captures[0].Value.TrimEnd(',')).ToList(); var fun = @@ -217,43 +208,7 @@ namespace CHeaderToXML Version = Version, Extension = GetExtension(funcname), Profile = String.Empty, - Parameters = - from item in get_param.Matches(paramaters_string).OfType().Select(m => m.Captures[0].Value.TrimEnd(',')) - //paramaters_string.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries) - let tokens = item.Trim().Split(' ') - let is_function_pointer = item.Contains("(*") // This only occurs in function pointers, e.g. void (*pfn_notify)() or void (*user_func)() - let param_name = - is_function_pointer ? tokens[1].TrimStart('(', '*').Split(')')[0] : - (tokens.Last().Trim() != "*/" ? tokens.Last() : tokens[tokens.Length - 2]).Trim() - let param_type = - is_function_pointer ? "IntPtr" : - (from t in tokens where t.Trim() != "const" && t.Trim() != "unsigned" select t).First().Trim() - let has_array_size = array_size.IsMatch(param_name) - let indirection_level = - is_function_pointer ? 0 : - (from c in param_name where c == '*' select c).Count() + - (from c in param_type where c == '*' select c).Count() + - (from t in tokens where t == "***" select t).Count() * 3 + - (from t in tokens where t == "**" select t).Count() * 2 + - (from t in tokens where t == "*" select t).Count() + - (has_array_size ? 1 : 0) - let pointers = new string[] { "*", "*", "*", "*" } // for adding indirection levels (pointers) to param_type - where tokens.Length > 1 - select new - { - Name = (has_array_size ? array_size.Replace(param_name, "") : param_name).Replace("*", ""), // Pointers are placed into the parameter Type, not Name - Type = - is_function_pointer ? param_type : - (tokens.Contains("unsigned") && !param_type.StartsWith("byte") ? "u" : "") + // Make sure we don't ignore the unsigned part of unsigned parameters (e.g. unsigned int -> uint) - param_type.Replace("*", "") + String.Join("", pointers, 0, indirection_level), // Normalize pointer indirection level (place as many asterisks as in indirection_level variable) - Count = has_array_size ? Int32.Parse(array_size.Match(param_name).Value.Trim('[', ']')) : 0, - Flow = - param_name.EndsWith("ret") || - ((funcname.StartsWith("Get") || funcname.StartsWith("Gen")) && - indirection_level > 0 && - !(funcname.EndsWith("Info") || funcname.EndsWith("IDs") || funcname.EndsWith("ImageFormats"))) ? // OpenCL contains Get*[Info|IDs|ImageFormats] methods with 'in' pointer parameters - "out" : "in" - } + Parameters = GetParameters(funcname, parameters_string) }; XElement func = new XElement("function", new XAttribute("name", fun.Name)); @@ -296,7 +251,6 @@ namespace CHeaderToXML line.StartsWith("GLAPI") || line.StartsWith("EGLAPI") || line.StartsWith("extern CL_API_ENTRY")); - var signatures = lines.Aggregate( new List(), (List acc, string line) => @@ -314,6 +268,73 @@ namespace CHeaderToXML return signatures; } + class Parameter + { + public string Name { get; set; } + public string Type { get; set; } + public int Count { get; set; } + public string Flow { get; set; } + } + + // This regex matches function parameters. + // The first part matches function pointers in the following format: + // '[return type] (*[function pointer name])([parameter list]) [parameter name] + // where [parameter name] may or may not be in comments. + // The second part (after the '|') matches parameters of the following formats: + // '[parameter type] [parameter name]', '[parameter type] [pointer] [parameter name]', 'const [parameter type][pointer] [parameter name]' + // where [parameter name] may be inside comments (/* ... */) and [pointer] is '', '*', '**', etc. + static readonly Regex get_param = new Regex( + @"(\w+\s\(\*\w+\)\s*\(.*\)\s*(/\*.*?\*/|\w+)? | (const\s*)? (\w+\s*)+ (\**\s*\**) (/\*.*?\*/|\w+(\[.*?\])?)) ,?", + RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); + + IEnumerable GetParameters(string funcname, string parameters_string) + { + var parameters = + get_param.Matches(parameters_string).OfType().Select(m => m.Captures[0].Value.TrimEnd(',')); + + foreach (var item in parameters) + { + var tokens = item.Trim().Split(' '); + // This only occurs in function pointers, e.g. void (*pfn_notify)() or void (*user_func)() + var is_function_pointer = item.Contains("(*"); + var param_name = + is_function_pointer ? tokens[1].TrimStart('(', '*').Split(')')[0] : + (tokens.Last().Trim() != "*/" ? tokens.Last() : tokens[tokens.Length - 2]).Trim(); + var param_type = + is_function_pointer ? "IntPtr" : + (from t in tokens where t.Trim() != "const" && t.Trim() != "unsigned" select t).First().Trim(); + var has_array_size = array_size.IsMatch(param_name); + var indirection_level = + is_function_pointer ? 0 : + (from c in param_name where c == '*' select c).Count() + + (from c in param_type where c == '*' select c).Count() + + (from t in tokens where t == "***" select t).Count() * 3 + + (from t in tokens where t == "**" select t).Count() * 2 + + (from t in tokens where t == "*" select t).Count() + + (has_array_size ? 1 : 0); + // for adding indirection levels (pointers) to param_type + var pointers = new string[] { "*", "*", "*", "*" }; + + if (tokens.Length > 1) + { + // Pointers are placed into the parameter Type, not Name + var name = (has_array_size ? array_size.Replace(param_name, "") : param_name).Replace("*", ""); + var type = is_function_pointer ? param_type : + (tokens.Contains("unsigned") && !param_type.StartsWith("byte") ? "u" : "") + // Make sure we don't ignore the unsigned part of unsigned parameters (e.g. unsigned int -> uint) + param_type.Replace("*", "") + String.Join("", pointers, 0, indirection_level); // Normalize pointer indirection level (place as many asterisks as in indirection_level variable) + var count = has_array_size ? Int32.Parse(array_size.Match(param_name).Value.Trim('[', ']')) : 0; + var flow = + param_name.EndsWith("ret") || + ((funcname.StartsWith("Get") || funcname.StartsWith("Gen")) && + indirection_level > 0 && + !(funcname.EndsWith("Info") || funcname.EndsWith("IDs") || funcname.EndsWith("ImageFormats"))) ? // OpenCL contains Get*[Info|IDs|ImageFormats] methods with 'in' pointer parameters + "out" : "in"; + + yield return new Parameter { Name = name, Type = type, Count = count, Flow = flow }; + } + } + } + void GetFunctionNameAndType(string[] words, out string funcname, out string rettype) { funcname = null;