Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

C# CodeDOM parser

, 27 Jun 2002
This is a utility which parses C# source code and creates the CODEDOM tree of the code.
cscodedomparser01.zip
CSParser
bin
Debug
Release
CodeTreeView
App.ico
bin
Debug
CodeTreeView.csproj.user
obj
Debug
temp
TempPE
cs-parser-modified.jay
cs-parser.jay
CSParser.csproj.user
CSParser.suo
jay
.cvsignore
ACKNOWLEDGEMENTS
ChangeLog
closure.o
conflict
CVS
Entries
Repository
Root
CVS
Entries
Entries.Log
Repository
Root
depend
error.o
jay.1
jay.exe
lalr.o
lr0.o
main.o
makefile
mkpar.o
NEW_FEATURES
NOTES
output.o
reader.o
README
README.jay
recover
CVS
Entries
Repository
Root
skeleton
symtab.o
verbose.o
warshall.o
NUnitTests
bin
Debug
Release
NUnitTests.csproj.user
obj
Debug
temp
TempPE
Release
temp
TempPE
TestFiles
obj
Debug
temp
TempPE
Release
temp
TempPE
testParser
bin
Debug
obj
Debug
temp
TempPE
testParser
App.ico
bin
Debug
Release
obj
Debug
temp
TempPE
Release
temp
TempPE
testParser.csproj.user
// CodeDomBuilder.cs: Builds  CodeDom Tree
//
// Written by IZ for purposes of CS CODEDOM Parser, 2002
//(c) 2002 Ivan Zderadicka (ivan.zderadicka@seznam.cz)

using System;
using System.CodeDom;
using Mono.CSharp;
using System.Diagnostics;
using System.Runtime;

namespace IvanZ.CSParser
{
	/// <summary>
	/// Summary description for CodeDomBuilder.
	/// </summary>
	public class CodeDomBuilder
	{
		
		private string sourceName;
		private Tokenizer lex;
		private CommentBuilder cmtBuilder;

		private CodeObject parent;
		public virtual CodeObject CurrParent
		{
			get 
			{
				return parent;
			}
			
		}
		public virtual void Up()
		{
			parent=(CodeObject) parent.UserData["Parent"];
			Debug.Assert(parent!=null, "Parent is null!!");
			//Clear any unused comments, when exiting level
			cmtBuilder.ClearComments();
		}
		
		private CodeCompileUnit compUnit;
		public virtual CodeCompileUnit CurrCompileUnit 
		{
			get 
			{
				return compUnit;
			}
		}

		private CodeNamespace ns;
		public virtual CodeNamespace CurrNamespace
		{
			get
			{
				return ns;
			}
			set
			{
				ns = value;
			}
		}

		private CodeTypeDeclaration type;
		public virtual CodeTypeDeclaration CurrType
		{
			get 
			{
				return type;
			}
			set
			{
				type=value;
			}
		}
		
		private CodeTypeMember member;
		public virtual CodeTypeMember CurrMember
		{
			get
			{
				return member;
			}
			set
			{
				member=value;
			}
		}

		private bool StartCmtAdded=false;

		public CodeDomBuilder(string name, Tokenizer lexer, CommentBuilder cb)
		{
			compUnit= new CodeCompileUnit();
			parent = compUnit;
			this.sourceName=name;
			lex=lexer;
			cmtBuilder=cb;

			// creates default NS - root ns (without name)
			
				CurrNamespace= new CodeNamespace();
				CurrNamespace.UserData["Location"]=new CodeLinePragma(sourceName, 0);
				CurrNamespace.UserData["Parent"]=CurrCompileUnit;
				CurrCompileUnit.Namespaces.Add(CurrNamespace);
				parent = CurrNamespace;
			      
			

			
		}

		public virtual void AddNamespace(string name) 
		{
			//no nested ns
			if ( ((CodeNamespace) parent).Name!="")
			{
				Report.Warning(9002,lex.Location,
					"No nested namespaces, they are not supported in CODEDOM, we try to flatten hierarchy, but no guarantee that it works for all cases");
				name = CurrNamespace.Name+"."+name;
			}
			CurrNamespace= new CodeNamespace(name);
			CurrNamespace.UserData["Location"]=new CodeLinePragma(sourceName,lex.Line);
			CurrNamespace.UserData["Parent"]=parent;
			
			CurrCompileUnit.Namespaces.Add(CurrNamespace);
			CurrNamespace.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();
			parent = CurrNamespace;
		}

		public virtual void AddUsingDirective(string name)
		{
			
			CodeNamespaceImport i = new CodeNamespaceImport(name);
			i.UserData["Location"] = new CodeLinePragma(sourceName, lex.Line);
			i.UserData["Parent"]= parent;
			CurrNamespace.Imports.Add(i);
			//If we are in the default ns and no starting comments were already added
			if (CurrCompileUnit.Namespaces.Count==1 && !StartCmtAdded)
			{
				CurrNamespace.Comments.AddRange(cmtBuilder.CurrComments);
				cmtBuilder.ClearComments();
				StartCmtAdded=true;
			}
			cmtBuilder.ClearComments();
		}

		public virtual void AddType(string name, ModifierAttribs atribs, Types type, 
			CodeTypeReferenceCollection bases, bool classScope, 
			CodeAttributeDeclarationCollection atrs)
		{
			CodeTypeDeclaration c= new CodeTypeDeclaration(name);
			c.UserData["Location"]=new CodeLinePragma(sourceName, lex.Line);
			c.UserData["Parent"]=parent;
			if (!Modifiers.CheckTypeModifiers(atribs, classScope, type))
			{
				Location l = lex.Location;
				Report.Error (9001, l, "Modifier(s) not allowed in this scope are used for " +type.ToString()+" "+ name );
			}
			Modifiers.SetElemModifiers(c, atribs, classScope);
			// Set  type of the type
			switch (type)
			{
				case Types.Class:
					c.IsClass=true;
					break;
				case Types.Interface:
					c.IsInterface=true;
					break;
				case Types.Struct:
					c.IsStruct=true;
					break;
				case Types.Enum:
					c.IsEnum=true;
					break;
			}

			if (bases!= null)
				c.BaseTypes.AddRange(bases);
			if (classScope)
				((CodeTypeDeclaration) parent).Members.Add(c);
			else
				CurrNamespace.Types.Add(c);
			AddAttributeToMemberMultiple(atrs, c,AttributeTargets.Type); 
			parent=c;
			CurrType=c;
			c.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();

			

		}

		public virtual void AddDelegate(string name, ModifierAttribs atribs, 
			CodeParameterDeclarationExpressionCollection pars,
			CodeTypeReference returnType, bool classScope, 
			CodeAttributeDeclarationCollection atrs)
		{
			CodeTypeDelegate c= new CodeTypeDelegate(name);
			c.UserData["Location"]=new CodeLinePragma(sourceName, lex.Line);
			c.UserData["Parent"]=parent;
			Types type= Types.Delegate;
			if (!Modifiers.CheckTypeModifiers(atribs, classScope, type))
			{
				Location l = lex.Location;
				Report.Error (9001, l, "Modifier(s) not allowed in this scope are used for " +type.ToString()+" "+ name );
			}
			Modifiers.SetElemModifiers(c, atribs, classScope);
			

			if (returnType!= null)
				c.ReturnType=returnType;
			if (pars !=null)
				c.Parameters.AddRange(pars);
			if (classScope)
				((CodeTypeDeclaration) parent).Members.Add(c);
			else
				CurrNamespace.Types.Add(c);
			AddAttributeToMemberMultiple(atrs, c,AttributeTargets.Type|AttributeTargets.Return); 
			CurrType=c;
			c.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();

			

		}
		
		public virtual void AddFieldMultiple(CodeTypeMemberCollection memberCollection, 
			ModifierAttribs atribs, CodeTypeReference fieldType, 
			Members type, CodeAttributeDeclarationCollection atrs)
		{
			
			
			foreach (CodeMemberField m in memberCollection)
			{
				AddField(m,atribs, fieldType, type, atrs);
			}

		}

		
		public virtual void AddField(string name, 
			ModifierAttribs atribs, CodeTypeReference fieldType, 
			Members type, CodeAttributeDeclarationCollection atrs)
		{
			CodeMemberField m= new CodeMemberField();
			m.Name=name;
			m.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();
			AddField(m,atribs, fieldType, type, atrs);
		}
		public virtual void AddField(CodeMemberField m, 
			ModifierAttribs atribs, CodeTypeReference fieldType, 
			Members type, CodeAttributeDeclarationCollection atrs)
		{
			if (type == Members.Constant)
				atribs|=ModifierAttribs.Const;

			m.UserData["Location"] = new CodeLinePragma(sourceName, lex.Line);
			m.UserData["Parent"]= parent;
			m.Type=fieldType;

			if (!Modifiers.CheckMemberModifiers(atribs , type))
			{
				Location l = lex.Location;
				Report.Error (9001, l, "Modifier(s) not allowed in this scope are used for " +type.ToString()+" "+ m.Name );
			}
			Modifiers.SetElemModifiers(m, atribs, false);

			AddAttributeToMemberMultiple(atrs, m,AttributeTargets.Field); 
			CurrType.Members.Add(m);
			CurrMember=m;

		}

		public virtual void AddMethod(string name, ModifierAttribs atribs, 
			CodeTypeReference returnType,
			CodeParameterDeclarationExpressionCollection pars,
			Members type, CodeAttributeDeclarationCollection atrs)
		{
			CodeMemberMethod m;
			
			if (name=="Main") 
				m=new CodeEntryPointMethod();
			else
				m= new CodeMemberMethod();
			m.Name=name;
			if (returnType!= null)
				m.ReturnType=returnType;
			if (pars !=null)
				m.Parameters.AddRange(pars);

			m.UserData["Location"] = new CodeLinePragma(sourceName, lex.Line);
			m.UserData["Parent"]= parent;

			if (!Modifiers.CheckMemberModifiers(atribs , type))
			{
				Location l = lex.Location;
				Report.Error (9001, l, "Modifier(s) not allowed in this scope are used for " +type.ToString()+" "+ m.Name );
			}
			Modifiers.SetElemModifiers(m, atribs, false);

			AddAttributeToMemberMultiple(atrs, m,AttributeTargets.Method|AttributeTargets.Return); 
			CurrType.Members.Add(m);
			CurrMember=m;
			parent=m;
			m.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();

		}

		public virtual void AddProperty(string name, ModifierAttribs atribs, 
			CodeTypeReference propType,
			CodeParameterDeclarationExpressionCollection pars,
			Members type, CodeAttributeDeclarationCollection atrs)
		{
			CodeMemberProperty m= new CodeMemberProperty();
			m.Name=name;
			m.Type=propType;
			if (pars !=null)
				m.Parameters.AddRange(pars);

			m.UserData["Location"] = new CodeLinePragma(sourceName, lex.Line);
			m.UserData["Parent"]= parent;

			if (!Modifiers.CheckMemberModifiers(atribs , type))
			{
				Location l = lex.Location;
				Report.Error (9001, l, "Modifier(s) not allowed in this scope are used for " +type.ToString()+" "+ m.Name );
			}
			Modifiers.SetElemModifiers(m, atribs, false);
			AddAttributeToMemberMultiple(atrs, m,AttributeTargets.Property); 
			CurrType.Members.Add(m);
			CurrMember=m;
			parent=m;
			m.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();

		}

		public virtual void AddEvent(CodeMemberEvent m, ModifierAttribs atribs,
			CodeTypeReference evType, Members type, CodeAttributeDeclarationCollection atrs)
		{
			
			m.Type=evType;
			

			m.UserData["Location"] = new CodeLinePragma(sourceName, lex.Line);
			m.UserData["Parent"]= parent;

			if (!Modifiers.CheckMemberModifiers(atribs , type))
			{
				Location l = lex.Location;
				Report.Error (9001, l, "Modifier(s) not allowed in this scope are used for " +type.ToString()+" "+ m.Name );
			}
			Modifiers.SetElemModifiers(m, atribs, false);
			AddAttributeToMemberMultiple(atrs, m,AttributeTargets.Event|AttributeTargets.Field|AttributeTargets.Method); 
			CurrType.Members.Add(m);
			CurrMember=m;
			parent=m;

		}

		public virtual void AddEvent(string name, ModifierAttribs atribs,
			CodeTypeReference evType, Members type, CodeAttributeDeclarationCollection atrs)
		{
			CodeMemberEvent e= new CodeMemberEvent();
			e.Name=name;
			e.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();
			AddEvent(e,atribs, evType,type, atrs);
		}

		public virtual void AddEventMultiple (CodeTypeMemberCollection names, ModifierAttribs atribs, 
			CodeTypeReference evType,
			Members type, CodeAttributeDeclarationCollection atrs)
		{
			foreach (CodeMemberField m in names)
			{
				CodeMemberEvent e =new CodeMemberEvent();
				e.Name=m.Name;
				e.Comments.AddRange(m.Comments);
				AddEvent(e, atribs, evType, type, atrs);
			}
		}


		public virtual void AddConstructor(ConstructorDecl d, ModifierAttribs atribs, 
			Members type, CodeAttributeDeclarationCollection atrs)
		{

			if (d.Name!= ((CodeTypeDeclaration) parent).Name)
			{
				Location l = lex.Location;
				Report.Error (9006, l, "Metod " + d.Name + " must have return type (or  it's mistyped constructor name)" );
			}

			CodeMemberMethod m;
			if ((atribs & ModifierAttribs.Static)!=0)
			{
				if (d.Params!=null)

				{
					Location l = lex.Location;
					Report.Error (9007, l, "Static constructor must be parameterless");
				}
				m=new CodeTypeConstructor();
				type=Members.StaticConstructor;
			}
			else
			{
				m=new CodeConstructor();
			}
			
			
			m.Name=d.Name;
			if (d.Params !=null)
				m.Parameters.AddRange(d.Params);

			m.UserData["Location"] = new CodeLinePragma(sourceName, lex.Line);
			m.UserData["Parent"]= parent;

			if (!Modifiers.CheckMemberModifiers(atribs , type))
			{
				Location l = lex.Location;
				Report.Error (9001, l, "Modifier(s) not allowed in this scope are used for " +type.ToString()+" "+ m.Name );
			}
			Modifiers.SetElemModifiers(m, atribs, false);

			AddAttributeToMemberMultiple(atrs, m,AttributeTargets.Method); 
			CurrType.Members.Add(m);
			CurrMember=m;
			parent=m;
			m.Comments.AddRange(cmtBuilder.CurrComments);
			cmtBuilder.ClearComments();


		}

		public virtual CodeExpression ResolveIdentifier(string qname)
		{
			//basically it needs lookup in the and resolving based on existing names
			//now it is just based on the stupid algorithm - everything which dont have 
			// dot is variable otherwise it is resolved to typereference plus member access

			if (qname.IndexOf('.')>-1)
			{
				int i=qname.LastIndexOf('.');
				CodeTypeReferenceExpression r= new CodeTypeReferenceExpression(qname.Substring(0, i));
				return new CodeFieldReferenceExpression(r,qname.Substring(i+1));
			}
			else
			{
				return new CodeVariableReferenceExpression(qname);
			}
		}

		public virtual void AddAssemblyAttributeMultiple(CodeAttributeDeclarationCollection atrs)
		{
			if (atrs != null)
			foreach(CodeAttributeDeclaration d in atrs)
				AddAssemblyAttribute(d);
		}
		public virtual void AddAssemblyAttribute(CodeAttributeDeclaration a)
		{
			CodeAttributeDeclarationExt aExt = (CodeAttributeDeclarationExt) a;
			if (aExt.Target != AttributeTargets.Assembly && aExt.Target != AttributeTargets.Module)
			{
				Report.Error(9015, lex.Location, "Attribute target not allowed in global scope");
				return;
			}
			CurrCompileUnit.AssemblyCustomAttributes.Add(a);
			
		}

		protected virtual void AddAttributeToMember(CodeAttributeDeclaration a, 
			CodeTypeMember m, AttributeTargets allowedTargets)
		{
			CodeAttributeDeclarationExt aExt = (CodeAttributeDeclarationExt) a;
			if (aExt.Target != 0 && ((aExt.Target &  allowedTargets)==0) && 
				((aExt.Target & AttributeTargets.Assembly)==0)
				&& (aExt.Target & AttributeTargets.Module)==0)
			{
				Report.Error(9015, lex.Location, "Attribute target not allowed in this scope");
				return;
			}
			else if (((aExt.Target & AttributeTargets.Assembly)!=0)||
				 ((aExt.Target & AttributeTargets.Module)!=0))
			{
				AddAssemblyAttribute(a);
				return;
			}
			m.CustomAttributes.Add(a);

		}

		protected virtual void AddAttributeToMemberMultiple(CodeAttributeDeclarationCollection atrs, 
			CodeTypeMember m, AttributeTargets allowedTargets)
		{
			if (atrs != null)
				foreach(CodeAttributeDeclaration d in atrs)
					AddAttributeToMember(d, m, allowedTargets);

		}

		public virtual void AddAttributeToParamMultiple(CodeAttributeDeclarationCollection atrs, 
			CodeParameterDeclarationExpression m)
		{
			if (atrs != null)
				foreach(CodeAttributeDeclaration d in atrs)
					AddAttributeToParam(d, m);

		}

		public virtual void AddAttributeToParam(CodeAttributeDeclaration a, 
			CodeParameterDeclarationExpression m)
		{
			CodeAttributeDeclarationExt aExt = (CodeAttributeDeclarationExt) a;
			if (aExt.Target != 0 && ((aExt.Target &  AttributeTargets.Param)==0))
			{
				Report.Error(9015, lex.Location, "Attribute target not allowed in this scope");
				return;
			}
			
			m.CustomAttributes.Add(a);

		}

		
		
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Ivan Zderadièka

Czech Republic Czech Republic
No Biography provided

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 28 Jun 2002
Article Copyright 2002 by Ivan Zderadièka
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid