public static TypeReference ParseTypeReference (Tokenizer tokenizer) { TypeReference tr = new TypeReference (); StringBuilder result = new StringBuilder (); if (tokenizer.Accept (Token2Type.Identifier, "const")) tr.IsConst = true; if (tokenizer.Accept (Token2Type.Identifier, "unsigned")) result.Append ("unsigned"); if (tokenizer.Accept (Token2Type.Identifier, "const")) tr.IsConst = true; result.Append (tokenizer.GetIdentifier ()); if (tokenizer.Accept (Token2Type.Punctuation, ":")) { tokenizer.AcceptOrThrow (Token2Type.Punctuation, ":"); result.Append ("::"); result.Append (tokenizer.GetIdentifier ()); } if (tokenizer.Accept (Token2Type.Identifier, "const")) tr.IsConst = true; while (tokenizer.Accept (Token2Type.Punctuation, "*")) result.Append ("*"); if (tokenizer.Accept (Token2Type.Identifier, "const")) tr.IsConst = true; if (tokenizer.Accept (Token2Type.Punctuation, "&")) result.Append ("&"); if (tokenizer.Accept (Token2Type.Identifier, "const")) tr.IsConst = true; //Console.WriteLine ("ParseTypeReference: parsed '{0}'", result.ToString ()); tr.Value = result.ToString (); return tr; }
static bool ParseMembers (MemberInfo parent, Tokenizer tokenizer) { Annotations properties = new Annotations (); TypeInfo parent_type = parent as TypeInfo; string accessibility; TypeReference returntype; bool is_dtor; bool is_ctor; bool is_virtual; bool is_static; bool is_const; bool is_extern; string name; //Console.WriteLine ("ParseMembers ({0})", type.Name); do { returntype = null; is_dtor = is_ctor = is_virtual = is_static = false; is_extern = is_const = false; name = null; properties = new Annotations (); if (parent_type != null) accessibility = parent_type.IsStruct ? "public" : "private"; else accessibility = "public"; try { if (tokenizer.Accept (Token2Type.Punctuation, ";")) continue; } catch { return false; } if (tokenizer.CurrentToken.value == "}") return true; while (tokenizer.CurrentToken.type == Token2Type.CommentProperty) { properties.Add (tokenizer.CurrentToken.value); tokenizer.Advance (true); } //Console.WriteLine ("ParseMembers: Current token: {0}", tokenizer.CurrentToken); if (tokenizer.CurrentToken.type == Token2Type.Identifier) { string v = tokenizer.CurrentToken.value; switch (v) { case "public": case "protected": case "private": accessibility = v; tokenizer.Advance (true); tokenizer.Accept (Token2Type.Punctuation, ":"); continue; case "enum": ParseEnum (properties, parent, tokenizer); continue; case "friend": while (!tokenizer.Accept (Token2Type.Punctuation, ";")) { tokenizer.Advance (true); } continue; case "struct": case "class": case "union": if (!ParseClassOrStruct (properties, parent, tokenizer)) return false; continue; case "typedef": StringBuilder requisite = new StringBuilder (); requisite.Append (tokenizer.CurrentToken.value); requisite.Append (' '); tokenizer.Advance (true); while (!tokenizer.Accept (Token2Type.Punctuation, ";")) { requisite.Append (tokenizer.CurrentToken.value); requisite.Append (' '); if (tokenizer.CurrentToken.value == "{") { tokenizer.Advance (true); while (!tokenizer.Accept (Token2Type.Punctuation, "}")) { requisite.Append (tokenizer.CurrentToken.value); requisite.Append (' '); tokenizer.Advance (true); } requisite.Append (tokenizer.CurrentToken.value); requisite.Append (' '); } tokenizer.Advance (true); } requisite.Append (";"); if (properties.ContainsKey ("CBindingRequisite")) cbinding_requisites.AppendLine (requisite.ToString ()); continue; case "EVENTHANDLER": while (!tokenizer.Accept (Token2Type.Punctuation, ";")) tokenizer.Advance (true); continue; case "template": tokenizer.Advance (true); tokenizer.AcceptOrThrow (Token2Type.Punctuation, "<"); tokenizer.AcceptOrThrow (Token2Type.Identifier, "typename"); tokenizer.GetIdentifier (); tokenizer.AcceptOrThrow (Token2Type.Punctuation, ">"); continue; case "using": tokenizer.Advance (true); continue; case "namespace": tokenizer.Advance (true); tokenizer.GetIdentifier (); tokenizer.Accept (Token2Type.Punctuation, "{"); continue; case "mutable": tokenizer.Advance (true); continue; } } do { if (tokenizer.Accept (Token2Type.Identifier, "virtual")) { is_virtual = true; continue; } if (tokenizer.Accept (Token2Type.Identifier, "static")) { is_static = true; continue; } if (tokenizer.Accept (Token2Type.Identifier, "const")) { is_const = true; continue; } if (tokenizer.Accept (Token2Type.Identifier, "extern")) { is_extern = true; continue; } if (tokenizer.Accept (Token2Type.Identifier, "volatile")) { continue; } if (tokenizer.Accept (Token2Type.Identifier, "G_GNUC_INTERNAL")) { continue; } break; } while (true); if (is_extern && tokenizer.Accept (Token2Type.Literal, "C")) { tokenizer.SyncWithEndBrace (); continue; } if (tokenizer.Accept (Token2Type.Punctuation, "~")) { is_dtor = true; if (!is_virtual) { TypeInfo ti = parent as TypeInfo; if (ti != null && ti.Base != null) Console.WriteLine ("The class {0} has a non-virtual destructor, and it's base class is {2} ({1}).", parent.Name, parent.Header, ti != null && ti.Base != null ? ti.Base.Value : "<none>"); } } if (is_dtor) { name = "~" + tokenizer.GetIdentifier (); returntype = new TypeReference ("void"); } else { returntype = ParseTypeReference (tokenizer); if (tokenizer.CurrentToken.value == "<") { tokenizer.Advance (true); while (!tokenizer.Accept (Token2Type.Punctuation, ">")) tokenizer.Advance (true); } if (returntype.Value == parent.Name && tokenizer.CurrentToken.value == "(") { is_ctor = true; name = returntype.Value; returntype.Value += "*"; } else { name = tokenizer.GetIdentifier (); } } returntype.IsConst = is_const; returntype.IsReturnType = true; //Console.WriteLine ("ParseMembers: found member '{0}' is_ctor: {1}", name, is_ctor); if (tokenizer.Accept (Token2Type.Punctuation, "(")) { // Method MethodInfo method = new MethodInfo (); method.Header = tokenizer.CurrentFile; method.Parent = parent; method.Annotations = properties; method.Name = name; method.IsConstructor = is_ctor; method.IsDestructor = is_dtor; method.IsVirtual = is_virtual; method.IsStatic = is_static; method.IsPublic = accessibility == "public"; method.IsPrivate = accessibility == "private"; method.IsProtected = accessibility == "protected"; method.ReturnType = returntype; //Console.WriteLine ("ParseMembers: found method '{0}' is_ctor: {1}", name, is_ctor); if (!tokenizer.Accept (Token2Type.Punctuation, ")")) { string param_value = null; do { ParameterInfo parameter = new ParameterInfo (method); while (tokenizer.CurrentToken.type == Token2Type.CommentProperty) { parameter.Annotations.Add (tokenizer.CurrentToken.value); tokenizer.Advance (true); } if (tokenizer.Accept (Token2Type.Punctuation, ".") && tokenizer.Accept (Token2Type.Punctuation, ".") && tokenizer.Accept (Token2Type.Punctuation, ".")) { // ... variable argument declaration parameter.ParameterType = new TypeReference ("..."); } else { if (tokenizer.CurrentToken.type == Token2Type.Identifier) { if (tokenizer.Accept (Token2Type.Identifier, "Moonlight")) { tokenizer.Accept (Token2Type.Punctuation, ":"); tokenizer.Accept (Token2Type.Punctuation, ":"); } } parameter.ParameterType = ParseTypeReference (tokenizer); } if (tokenizer.CurrentToken.value != "," && tokenizer.CurrentToken.value != ")") { parameter.Name = tokenizer.GetIdentifier (); if (tokenizer.Accept (Token2Type.Punctuation, "[")) { if (tokenizer.CurrentToken.type == Token2Type.Identifier) tokenizer.Advance (true); tokenizer.AcceptOrThrow (Token2Type.Punctuation, "]"); } if (tokenizer.Accept (Token2Type.Punctuation, "=")) { param_value = string.Empty; if (tokenizer.Accept (Token2Type.Punctuation, "-")) param_value = "-"; param_value += tokenizer.GetIdentifier (); if (tokenizer.Accept (Token2Type.Punctuation, ":")) { tokenizer.AcceptOrThrow (Token2Type.Punctuation, ":"); param_value += "::" + tokenizer.GetIdentifier (); } } } method.Parameters.Add (parameter); //Console.WriteLine ("ParseMember: got parameter, type: '{0}' name: '{1}' value: '{2}'", parameter.ParameterType.Value, parameter.Name, param_value); } while (tokenizer.Accept (Token2Type.Punctuation, ",")); tokenizer.AcceptOrThrow (Token2Type.Punctuation, ")"); } parent.Children.Add (method); //Allow const member functions, ignore the const keyword tokenizer.Accept (Token2Type.Identifier, "const"); if (tokenizer.CurrentToken.value == "{") { //Console.WriteLine ("ParseMember: member has body, skipping it"); tokenizer.SyncWithEndBrace (); } else if (is_ctor && tokenizer.Accept (Token2Type.Punctuation, ":")) { // ctor method implemented in header with field initializers and/or base class ctor call tokenizer.FindStartBrace (); tokenizer.SyncWithEndBrace (); //Console.WriteLine ("ParseMember: skipped ctor method implementation"); } else if (tokenizer.Accept (Token2Type.Punctuation, "=")) { // pure virtual method tokenizer.AcceptOrThrow (Token2Type.Identifier, "0"); tokenizer.AcceptOrThrow (Token2Type.Punctuation, ";"); method.IsAbstract = true; } else { if (tokenizer.Accept (Token2Type.Identifier, "__attribute__")) { tokenizer.AcceptOrThrow (Token2Type.Punctuation, "("); tokenizer.AcceptOrThrow (Token2Type.Punctuation, "("); if (tokenizer.CurrentToken.type == Token2Type.Identifier) tokenizer.Advance (true); tokenizer.AcceptOrThrow (Token2Type.Punctuation, ")"); tokenizer.AcceptOrThrow (Token2Type.Punctuation, ")"); } tokenizer.AcceptOrThrow (Token2Type.Punctuation, ";"); } } else { if (is_ctor || is_dtor) throw new Exception (string.Format ("Expected '(', not '{0}'", tokenizer.CurrentToken.value)); if (name == "operator") { while (true) { if (tokenizer.CurrentToken.value == ";") { // End of operator break; } else if (tokenizer.CurrentToken.value == "{") { // In-line implementation tokenizer.SyncWithEndBrace (); break; } tokenizer.Advance (true); } //Console.WriteLine ("ParseMembers: skipped operator"); } else { FieldInfo field = new FieldInfo (); field.IsConst = is_const; field.IsStatic = is_static; field.IsExtern = is_extern; field.Name = name; field.FieldType = returntype; field.IsPublic = accessibility == "public"; field.IsPrivate = accessibility == "private"; field.IsProtected = accessibility == "protected"; field.Annotations = properties; // Field do { //Console.WriteLine ("ParseMembers: found field '{0}'", name); field.Parent = parent; parent.Children.Add (field); if (tokenizer.Accept (Token2Type.Punctuation, "[")) { while (!tokenizer.Accept (Token2Type.Punctuation, "]")) { tokenizer.Advance (true); } } if (tokenizer.Accept (Token2Type.Punctuation, ":")) { field.BitField = tokenizer.GetIdentifier (); } if (tokenizer.Accept (Token2Type.Punctuation, ",")) { field = new FieldInfo (); if (tokenizer.Accept (Token2Type.Punctuation, "*")) { // ok } field.Name = tokenizer.GetIdentifier (); field.FieldType = returntype; continue; } if (tokenizer.Accept (Token2Type.Punctuation, "=")) { tokenizer.Advance (true); /* this can be an arbitrary long expression, sync with the ';'? */ } break; } while (true); tokenizer.Accept (Token2Type.Punctuation, ";"); } } } while (true); }
static void ParseEnum (Annotations properties, MemberInfo parent, Tokenizer tokenizer) { FieldInfo field; StringBuilder value = new StringBuilder (); TypeInfo type = new TypeInfo (); type.Annotations = properties; type.IsEnum = true; tokenizer.AcceptOrThrow (Token2Type.Identifier, "enum"); if (tokenizer.CurrentToken.type == Token2Type.Identifier) { type.Name = tokenizer.GetIdentifier (); } else { type.Name = "<anonymous>"; } parent.Children.Add (type); tokenizer.AcceptOrThrow (Token2Type.Punctuation, "{"); //Console.WriteLine ("ParseEnum: {0}", name); while (tokenizer.CurrentToken.type == Token2Type.Identifier) { field = new FieldInfo (); field.Name = tokenizer.GetIdentifier (); value.Length = 0; if (tokenizer.Accept (Token2Type.Punctuation, "=")) { while (tokenizer.CurrentToken.value != "," && tokenizer.CurrentToken.value != "}") { value.Append (" "); value.Append (tokenizer.CurrentToken.value); tokenizer.Advance (true); } } field.Value = value.ToString (); type.Children.Add (field); //Console.WriteLine ("ParseEnum: {0}: {1} {2} {3}", name, field, value.Length != 0 != null ? "=" : "", value); if (!tokenizer.Accept (Token2Type.Punctuation, ",")) break; } tokenizer.AcceptOrThrow (Token2Type.Punctuation, "}"); tokenizer.AcceptOrThrow (Token2Type.Punctuation, ";"); }
// Returns false if there are no more tokens (reached end of code) static bool ParseClassOrStruct (Annotations annotations, MemberInfo parent, Tokenizer tokenizer) { TypeInfo type = new TypeInfo (); type.Annotations = annotations; type.Header = tokenizer.CurrentFile; type.Parent = parent; type.IsPublic = tokenizer.Accept (Token2Type.Identifier, "public"); if (tokenizer.Accept (Token2Type.Identifier, "class")) { type.IsClass = true; } else if (tokenizer.Accept (Token2Type.Identifier, "struct")) { type.IsStruct = true; type.IsValueType = true; } else if (tokenizer.Accept (Token2Type.Identifier, "union")) { type.IsStruct = true; // Not entirely correct, but a union can be parsed as a struct type.IsValueType = true; } else { throw new Exception (string.Format ("Expected 'class' or 'struct', not '{0}'", tokenizer.CurrentToken.value)); } if (tokenizer.CurrentToken.type == Token2Type.Identifier) { type.Name = tokenizer.GetIdentifier (); } else { type.Name = "<anonymous>"; } if (tokenizer.Accept (Token2Type.Punctuation, ";")) { // A forward declaration. //Console.WriteLine ("ParseType: Found a forward declaration to {0}", type.Name); return true; } if (tokenizer.Accept (Token2Type.Punctuation, ":")) { if (!tokenizer.Accept (Token2Type.Identifier, "public") && type.IsClass) throw new Exception (string.Format ("The base class of {0} is not public.", type.Name)); type.Base = ParseTypeReference (tokenizer); // accept multiple inheritance the easy way while (tokenizer.CurrentToken.value == ",") { tokenizer.Accept (Token2Type.Punctuation, ","); while (tokenizer.CurrentToken.value != "," && tokenizer.CurrentToken.value != "{") tokenizer.GetIdentifier (); } //Console.WriteLine ("ParseType: Found {0}'s base class: {1}", type.Name, type.Base); } tokenizer.AcceptOrThrow (Token2Type.Punctuation, "{"); //Console.WriteLine ("ParseType: Found a type: {0} in {1}", type.Name, type.Header); parent.Children.Add (type); ParseMembers (type, tokenizer); tokenizer.AcceptOrThrow (Token2Type.Punctuation, "}"); if (tokenizer.CurrentToken.type == Token2Type.Identifier) tokenizer.Advance (true); if (tokenizer.CurrentToken.value != ";") throw new Exception (string.Format ("Expected ';', not '{0}'", tokenizer.CurrentToken.value)); return tokenizer.Advance (false); }