Click here to Skip to main content
15,893,622 members
Articles / Programming Languages / C#

A Simple Compiler for the Common Language Runtime

Rate me:
Please Sign up or sign in to vote.
4.89/5 (86 votes)
11 May 20039 min read 295.8K   5.1K   190  
An end-to-end example of a bottom up LALR(1) compiler for a fictitious language targeting the Common Language Runtime
/*
Magic IDE
Copyright (C) 2003  Michael Bebenita

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

using Crownwood.Magic;
using Crownwood.Magic.Docking;
using Crownwood.Magic.Common;

using UtilityLibrary.Menus;
using UtilityLibrary.CommandBars;
using UtilityLibrary.WinControls;
using UtilityLibrary.General;
using UtilityLibrary.Win32;
using UtilityLibrary.Collections;

using System.Diagnostics;
using System.IO;

using ICSharpCode.TextEditor;
using System.Runtime.InteropServices;

using Core;
using Core.Compilation;

namespace Magic_IDE
{
	public enum IconIndex
	{
		Project_Explorer = 51,
		Object_Explorer = 53,
		Parse_Tree = 4,
		New_Project = 65,
		New_File = 85,
		Open_Project = 84,
		Open_File = 35,
		Save_File = 0,
		Save_Files = 1,
		Output = 52,
		Build = 31,

		File = 88,
		Project = 51,

		Terminal = 7,
		NonTerminal = 6,

		Module = 6,
		Structure = 8,
		Function = 12,
		Variable = 16,
		Expression = 41,
		Body = 47
	}
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class IDE : System.Windows.Forms.Form
	{
		[DllImport("User32.Dll")]
		private static extern int SendMessage(IntPtr hWnd,int Msg,int  wParam,int  lParam);			
	

		private System.ComponentModel.IContainer components;

		public IDE()
		{
			//
			// Required for Windows Form Designer support
			//

			InitializeComponent();
			InitializeImageLists();
			InitializeDockingSystem();
			InitializeMenu();

			InitializeCompiler();

			UpdateUIState();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			// 
			// IDE
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(688, 422);
			this.Name = "IDE";
			this.Text = "Sharp IDE";
			this.Closing += new System.ComponentModel.CancelEventHandler(this.IDE_Closing);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			//Application.Run(new Test());
			Application.Run(new IDE());
		}

		private DockingManager m_Docker = null;
		private TreeView m_tvProjectExplorer = null;
		private TreeView m_tvObjectExplorer = null;
		private TreeView m_tvParseTree = null;
		private TreeView m_tvSyntaxTree = null;

		private RichTextBox m_Output = null;
		private Crownwood.Magic.Controls.TabControl m_Files = null;
		private StatusBar m_Status = null;
		private ImageList m_ImageList = null;

		private Language m_Language = null;

		private void InitializeCompiler()
		{
			m_Language = Language.FromFile("Sharp.cgt");
		}

		private void InitializeImageLists()
		{
			Bitmap strip = (Bitmap)Bitmap.FromFile("Images.bmp");
			m_ImageList = new ImageList();
			m_ImageList.ImageSize = new Size(16,16);
			m_ImageList.TransparentColor = Color.FromArgb(0,255,0);
			m_ImageList.Images.AddStrip(strip);
		}

		Content m_OutputContent = null;
		Content m_ProjectExplorerContent = null;
		Content m_ObjectExplorerContent = null;
		Content m_ParseTreeContent = null;
		Content m_SyntaxTreeContent = null;

		private void InitializeDockingSystem()
		{
			//
			// Setup File Tabs
			//

			m_Files = new Crownwood.Magic.Controls.TabControl();
			m_Files.Appearance = Crownwood.Magic.Controls.TabControl.VisualAppearance.MultiDocument;
			m_Files.Dock = DockStyle.Fill;
			m_Files.Style = Crownwood.Magic.Common.VisualStyle.IDE;
			m_Files.IDEPixelBorder = true;

			m_Files.ClosePressed += new EventHandler(OnFilesClosed);
			m_Files.PageGotFocus += new EventHandler(OnPageGotFocus);

			Controls.Add(m_Files);

			m_Docker = new DockingManager(this, Crownwood.Magic.Common.VisualStyle.IDE);

			//
			// Setup Output
			//

			m_Output = new RichTextBox();
			m_Output.WordWrap = false;
			m_Output.ScrollBars = RichTextBoxScrollBars.Both;
			m_Output.Font = new Font("Courier New",8);
			m_Output.BackColor = Color.Black;
			m_Output.ForeColor = Color.GreenYellow;

			m_OutputContent = m_Docker.Contents.Add(
				m_Output, "Output");
			m_OutputContent.ImageList = m_ImageList;
			m_OutputContent.ImageIndex = (int)IconIndex.Output;
			WindowContent bottomWindow = m_Docker.AddContentWithState(
				m_OutputContent, Crownwood.Magic.Docking.State.DockBottom) as WindowContent;

			//
			// Setup Project and Object explorers.
			//

			// Project Explorer
			m_tvProjectExplorer = new TreeView();
			m_tvProjectExplorer.ImageList = m_ImageList;
			m_tvProjectExplorer.DoubleClick += new EventHandler(OnProjectExplorerDoubleClick);
			m_ProjectExplorerContent = m_Docker.Contents.Add(
				m_tvProjectExplorer, "Project Explorer");
			m_ProjectExplorerContent.ImageList = m_ImageList;
			m_ProjectExplorerContent.ImageIndex = (int)IconIndex.Project_Explorer;

			WindowContent leftWindow = m_Docker.AddContentWithState(
				m_ProjectExplorerContent, Crownwood.Magic.Docking.State.DockLeft) as WindowContent;

			// Object Explorer
			m_tvObjectExplorer = new TreeView();
			m_tvObjectExplorer.ImageList = m_ImageList;
			m_ObjectExplorerContent = m_Docker.Contents.Add(
				m_tvObjectExplorer, "Object Explorer");
			m_ObjectExplorerContent.ImageList = m_ImageList;
			m_ObjectExplorerContent.ImageIndex = (int)IconIndex.Object_Explorer;
			m_Docker.AddContentToWindowContent(m_ObjectExplorerContent, leftWindow);

			// Parse Tree
			m_tvParseTree = new TreeView();
			m_tvParseTree.ImageList = m_ImageList;
			m_ParseTreeContent = m_Docker.Contents.Add(m_tvParseTree,"Parse Tree");
			m_ParseTreeContent.ImageList = m_ImageList;
			m_ParseTreeContent.ImageIndex = (int)IconIndex.Parse_Tree;
			m_Docker.AddContentToWindowContent(m_ParseTreeContent, leftWindow);

			// Syntax Tree
			m_tvSyntaxTree = new TreeView();
			m_tvSyntaxTree.ImageList = m_ImageList;
			m_SyntaxTreeContent = m_Docker.Contents.Add(m_tvSyntaxTree,"Syntax Tree");
			m_SyntaxTreeContent.ImageList = m_ImageList;
			m_SyntaxTreeContent.ImageIndex = (int)IconIndex.Parse_Tree;
			m_Docker.AddContentToWindowContent(m_SyntaxTreeContent, leftWindow);

			m_Status = new StatusBar();
			m_Status.Dock = DockStyle.Bottom;
			Controls.Add(m_Status);
			m_Docker.InnerControl = m_Files;
			m_Docker.OuterControl = m_Status;
			m_Docker.HideAllContents();
			m_Docker.ShowAllContents();
			m_Docker.LoadConfigFromFile("Config.dck");
		}

		private ReBar m_Toolbars = null;

		private ToolBarEx m_Menu = null;
			private ToolBarItem m_FileMenu = null;
				private MenuItemEx m_New = null;
					private MenuItemEx m_NewProject = null;
					private MenuItemEx m_NewFile = null;

				private MenuItemEx m_OpenProject = null;
				private MenuItemEx m_CloseProject = null;

				private MenuItemEx m_SaveFile = null;
				private MenuItemEx m_SaveAllFiles = null;

				private MenuItemEx m_Exit = null;
			private ToolBarItem m_ProjectMenu = null;
				private MenuItemEx m_AddNewFile = null;
				private MenuItemEx m_RemoveFile = null;
				private MenuItemEx m_DeleteFile = null;

			private ToolBarItem m_ViewMenu = null;
				private MenuItemEx m_ViewProjectExplorer = null;
				private MenuItemEx m_ViewObjectExplorer = null;
				private MenuItemEx m_ViewOutput = null;

			private ToolBarItem m_ToolsMenu = null;
				private MenuItemEx m_BuildParseTree = null;
				private MenuItemEx m_BuildSyntaxTree = null;
					
		private ToolBarEx m_Tools = null;
			private ToolBarItem m_NewTool = null;
				private MenuItemEx m_NewProjectTool = null;
				private MenuItemEx m_NewFileTool = null;
			private ToolBarItem m_AddNewFileTool = null;
			private ToolBarItem m_SaveFileTool = null;
			private ToolBarItem m_SaveAllFilesTool = null;
			private ToolBarItem m_BuildTool = null;

		private ToolBarEx m_FullScreenTools = null;
			private ToolBarItem m_FullScreenTool = null;

		private void InitializeMenu()
		{
			//
			// Menu
			//

			ToolBarEx m_Menu = new ToolBarEx(BarType.MenuBar);
			m_Menu.ImageList = m_ImageList;

			m_FileMenu = new ToolBarItem("&File");
				m_New = new MenuItemEx("&New",null);
					m_NewProject = new MenuItemEx("&Project",m_ImageList,(int)IconIndex.New_Project,Shortcut.CtrlShiftN,new EventHandler(OnNewProject));
					m_NewFile = new MenuItemEx("&File",m_ImageList,(int)IconIndex.New_File,Shortcut.CtrlN,new EventHandler(OnNewFile));
					m_New.MenuItems.Add(m_NewProject);
					m_New.MenuItems.Add(m_NewFile);

				m_OpenProject = new MenuItemEx("&Open Project",m_ImageList,(int)IconIndex.Open_Project,Shortcut.CtrlO,new EventHandler(OnOpenProject));
				m_CloseProject = new MenuItemEx("&Close Project",new EventHandler(OnCloseProject));
				m_SaveFile = new MenuItemEx("&Save File",m_ImageList,(int)IconIndex.Save_File,Shortcut.CtrlS ,new EventHandler(OnSaveFile));
				m_SaveAllFiles = new MenuItemEx("&Save All",m_ImageList,(int)IconIndex.Save_Files,Shortcut.CtrlShiftS,new EventHandler(OnSaveAllFiles));
				m_Exit = new MenuItemEx("&Exit",new EventHandler(OnExit));

			m_FileMenu.MenuItems.Add(m_New);
			m_FileMenu.MenuItems.Add(m_OpenProject);
			m_FileMenu.MenuItems.Add(m_CloseProject);
			m_FileMenu.MenuItems.Add(new MenuItemEx("-",null));
			m_FileMenu.MenuItems.Add(m_SaveFile);
			m_FileMenu.MenuItems.Add(m_SaveAllFiles);
			m_FileMenu.MenuItems.Add(new MenuItemEx("-",null));
			m_FileMenu.MenuItems.Add(m_Exit);

			m_ViewMenu = new ToolBarItem("&View");
			m_ViewProjectExplorer = new MenuItemEx("&Project Explorer",m_ImageList,(int)IconIndex.Project_Explorer,Shortcut.CtrlShiftP,new EventHandler(OnView));
			m_ViewObjectExplorer = new MenuItemEx("&Object Explorer",m_ImageList,(int)IconIndex.Object_Explorer,Shortcut.CtrlShiftB,new EventHandler(OnView));
			m_ViewOutput = new MenuItemEx("&Output",m_ImageList,(int)IconIndex.Output,Shortcut.CtrlShiftO,new EventHandler(OnView));

			m_ViewMenu.MenuItems.Add(m_ViewProjectExplorer);
			m_ViewMenu.MenuItems.Add(m_ViewObjectExplorer);
			m_ViewMenu.MenuItems.Add(m_ViewOutput);

			m_ProjectMenu = new ToolBarItem("&Project");
			m_ProjectMenu.DropDown += new EventHandler(OnProjectMenuDropDown);

				m_AddNewFile = new MenuItemEx("&Add Exisiting File",m_ImageList,(int)IconIndex.New_File,Shortcut.None,new EventHandler(OnAddFile));
				m_RemoveFile = new MenuItemEx("&Remove File",new EventHandler(OnRemoveFile),Shortcut.CtrlR);
				m_DeleteFile = new MenuItemEx("&Delete File",new EventHandler(OnDeleteFile),Shortcut.CtrlD);
				m_ProjectMenu.MenuItems.Add(m_AddNewFile);
				m_ProjectMenu.MenuItems.Add(m_RemoveFile);
				m_ProjectMenu.MenuItems.Add(m_DeleteFile);
				
			m_ToolsMenu = new ToolBarItem("&Tools");
			m_ToolsMenu.DropDown += new EventHandler(OnToolsMenuDropDown);
				m_BuildParseTree = new MenuItemEx("Build &Parse Tree",m_ImageList,(int)IconIndex.Parse_Tree,Shortcut.CtrlP,new EventHandler(OnBuildParseTree));
				m_BuildSyntaxTree = new MenuItemEx("Build &Syntax Tree",m_ImageList,(int)IconIndex.Parse_Tree,Shortcut.CtrlS,new EventHandler(OnBuildSyntaxTree));
				m_ToolsMenu.MenuItems.Add(m_BuildParseTree);
				m_ToolsMenu.MenuItems.Add(m_BuildSyntaxTree);

			m_Menu.Items.Add(m_FileMenu);
			m_Menu.Items.Add(m_ViewMenu);
			m_Menu.Items.Add(m_ProjectMenu);
			m_Menu.Items.Add(m_ToolsMenu);

			//
			// Toolbar
			//

			m_Tools = new ToolBarEx();
			m_Tools.ImageList = m_ImageList;

			m_NewTool = new ToolBarItem();
			m_NewTool.ImageListIndex = (int)IconIndex.New_Project;
			m_NewTool.Style = ToolBarItemStyle.DropDownButton;
			m_NewTool.DropDown += new EventHandler(OnToolbarDropDown);
			m_NewTool.Text = "New";
				m_NewProjectTool = new MenuItemEx("&Project",m_ImageList,(int)IconIndex.New_Project,Shortcut.None,new EventHandler(OnNewProject));
				m_NewFileTool = new MenuItemEx("&File",m_ImageList,(int)IconIndex.New_File,Shortcut.None,new EventHandler(OnNewFile));
			m_Tools.Items.Add(m_NewTool);

			m_AddNewFileTool = new ToolBarItem();
			m_AddNewFileTool.ImageListIndex = (int)IconIndex.New_File;
			m_AddNewFileTool.Style = ToolBarItemStyle.PushButton;
			m_AddNewFileTool.Text = "Add Existing File";
			m_AddNewFileTool.Click += new EventHandler(OnAddFile);
			m_Tools.Items.Add(m_AddNewFileTool);

			m_SaveFileTool = new ToolBarItem();
			m_SaveFileTool.ImageListIndex = (int)IconIndex.Save_File;
			m_SaveFileTool.Style = ToolBarItemStyle.PushButton;
			m_SaveFileTool.Text = "Save File";
			m_SaveFileTool.Click += new EventHandler(OnSaveFile);
			m_Tools.Items.Add(m_SaveFileTool);

			m_SaveAllFilesTool = new ToolBarItem();
			m_SaveAllFilesTool.ImageListIndex = (int)IconIndex.Save_Files;
			m_SaveAllFilesTool.Style = ToolBarItemStyle.PushButton;
			m_SaveAllFilesTool.Text = "Save All";
			m_SaveAllFilesTool.Click += new EventHandler(OnSaveAllFiles);
			m_Tools.Items.Add(m_SaveAllFilesTool);

			ToolBarItem separator = new ToolBarItem();
			separator.Style = ToolBarItemStyle.Separator;
			m_Tools.Items.Add(separator);
			
			m_BuildTool = new ToolBarItem();
			m_BuildTool.ImageListIndex = (int)IconIndex.Build;
			m_BuildTool.Style = ToolBarItemStyle.PushButton;
			m_BuildTool.Click += new EventHandler(OnBuild);
			m_BuildTool.Text = "Build";
			m_Tools.Items.Add(m_BuildTool);

			//
			// Full Screen Tools
			//

			m_FullScreenTools = new ToolBarEx();
			m_FullScreenTools.ImageList = m_ImageList;

			m_FullScreenTool = new ToolBarItem();
			m_FullScreenTool.Style = ToolBarItemStyle.PushButton;
			m_FullScreenTool.Text = "Full Screen";
			m_FullScreenTool.Click += new EventHandler(OnFullScreenTool);

			m_FullScreenTools.Items.Add(m_FullScreenTool);

			// ////////////////////////////

			m_Toolbars = new ReBar();
			m_Toolbars.Bands.Add(m_Menu);
			m_Toolbars.Bands.Add(m_Tools);
			m_Toolbars.Bands.Add(m_FullScreenTools);

			m_Toolbars.Dock = DockStyle.Top;
			Controls.Add(m_Toolbars);
		}

		private void IDE_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			m_Docker.SaveConfigToFile("Config.dck");
			CloseProject();
		}

		public bool m_bFullScreen = false;
		public Content [] m_VisibleContent = null;
		private void OnFullScreenTool(object sender, EventArgs e)
		{
			if(m_bFullScreen)
			{
				foreach(Content c in m_VisibleContent)
					m_Docker.ShowContent(c);
				m_bFullScreen = false;
			}
			else
			{
				int visible = 0;
				foreach(Content c in m_Docker.Contents)
					visible = c.Visible ? visible + 1: visible;
				m_VisibleContent = new Content [visible];

				int index = 0;
				foreach(Content c in m_Docker.Contents)
				{
					if(c.Visible)
					{
						m_VisibleContent[index] = c;
						index ++;
					}
				}
				m_Docker.HideAllContents();
				m_bFullScreen = true;
			}
		}

		private void OnView(object sender, EventArgs e)
		{
			if(sender == m_ViewObjectExplorer)
			{
				m_Docker.ShowContent(m_ObjectExplorerContent);
			}
			else if(sender == m_ViewProjectExplorer)
			{
				m_Docker.ShowContent(m_ProjectExplorerContent);
			}
			else if(sender == m_ViewOutput)
			{
				m_Docker.ShowContent(m_OutputContent);
			}
		}

		private void OnToolbarDropDown(object sender, EventArgs e)
		{
			ToolBarItem item = (ToolBarItem)sender;
			ContextMenu cm = new ContextMenu(new MenuItemEx[] {m_NewProjectTool,m_NewFileTool});
			Rectangle rc = item.ItemRectangle;
			Point pos = new Point(rc.Left, rc.Bottom);
			cm.Show(m_Tools, pos);
			
		}

		private void WriteAndScroll(RichTextBox textbox, string message)
		{
			textbox.AppendText(message + "\n");
			SendMessage(textbox.Handle,0xB6, 0, 1);
		}

		// ///////////////////////////////
		// ///////////////////////////////

		/// <summary>
		/// Load project.
		/// </summary>
		/// <param name="project"></param>
		private void LoadProject(Project project)
		{
			m_Project = project;

			//
			// Load project in project explorer.
			//

			m_tvProjectExplorer.HideSelection = false;
			m_tvProjectExplorer.Nodes.Clear();
			if(m_Project == null)
				return;

			TreeNode tnProject = new TreeNode(m_Project.Name,(int)IconIndex.Project,(int)IconIndex.Project );
			tnProject.Tag = m_Project;
			m_Project.Node = tnProject;

			foreach(ProjectFile file in m_Project.ProjectFiles)
			{
				TreeNode tnFile = new TreeNode(System.IO.Path.GetFileName(file.Path),(int)IconIndex.File,(int)IconIndex.File);
				tnFile.Tag = file;
				file.Node = tnFile;
				tnProject.Nodes.Add(tnFile);
			}
			
			m_tvProjectExplorer.Nodes.Add(tnProject);
			m_tvProjectExplorer.ExpandAll();

			m_Project.ProjectFiles.Added += new ProjectFileEventHandler(OnProjectFileAdded);
			m_Project.ProjectFiles.Removed += new ProjectFileEventHandler(OnProjectFileRemoved);

			//
			// TODO: Open opened files.
			//

			m_ProjectFiles = new ProjectFileCollection();
			m_ProjectFiles.Added += new ProjectFileEventHandler(OnProjectFileOpened);
			m_ProjectFiles.Removed += new ProjectFileEventHandler(OnProjectFileClosed);
		}


		/// <summary>
		/// Close loaded project.
		/// </summary>
		private void CloseProject()
		{
			if(m_Project == null)
				return;
			//
			// Clear project explorer.
			//

			m_tvProjectExplorer.Nodes.Clear();
			m_Project.Save();
			m_Project = null;

			//
			// TODO: Clear opened files.
			//
		}


		private void UpdateUIState()
		{
			m_AddNewFileTool.Enabled = (m_Project != null);
			m_CloseProject.Enabled = (m_Project != null);
			m_NewFile.Enabled = m_NewFileTool.Enabled = (m_Project != null);


			m_SaveFile.Enabled = m_SaveFileTool.Enabled = (m_ProjectFile != null);
			if(m_ProjectFile != null)
				m_SaveFile.Text = "S&ave " + m_ProjectFile.Name;
			else
				m_SaveFile.Text = "S&ave File";

			if(m_ProjectFile != null)
				m_SaveAllFiles.Enabled = m_SaveAllFilesTool.Enabled = (m_ProjectFiles.Count > 0);
			else
				m_SaveAllFiles.Enabled = m_SaveAllFilesTool.Enabled = false;
		}

		// ///////////////////////////////

		/// <summary>
		/// Currently opened project.
		/// </summary>
		private Project m_Project = null;
		
		/// <summary>
		/// Opened project files.
		/// </summary>
		private ProjectFileCollection m_ProjectFiles = null;

		/// <summary>
		/// Currently opened project file.
		/// </summary>
		private ProjectFile m_ProjectFile = null;

		//
		// UI Commands
		//

		/// <summary>
		///		UI command to build source program.
		/// </summary>
		private void OnBuild(object sender, EventArgs e)
		{
			if(m_ProjectFile == null)
				return;

			m_ProjectFile.Source.SaveFile(m_ProjectFile.Path);
			m_ProjectFile.IsChanged = false;

			try
			{
				m_Output.Clear();

				Scanner scanner = new Scanner(m_ProjectFile.Path,m_Language);
				Parser parser = new Parser(scanner,m_Language);

				parser.Error += new ParserEventHandler(OnParserError);
				Module module = parser.CreateSyntaxTree();

				Generator generator = new Generator(module);

				
				string path = Path.GetDirectoryName(m_Project.Path) + "\\" + module.Name + ".exe";
				
				if(File.Exists(path))
					File.Delete(path);
				
				generator.Compile(path);

				//
				// Use ildasm to decompile executable.
				//

				/*
				if(File.Exists("il.txt"))
					File.Delete("il.txt");

				Process ildasm = new Process();
				ildasm.StartInfo.FileName = "ildasm.exe";
				ildasm.StartInfo.Arguments = "/OUT=il.txt " + path;
				ildasm.Start();
				ildasm.WaitForExit();

				StreamReader il = File.OpenText("il.txt");
				WriteAndScroll(m_Output, il.ReadToEnd());
				il.Close();

				*/

				Process child = new Process();
				child.StartInfo.FileName = path;
				child.Start();
			
			}
			catch(Exception x)
			{
				WriteAndScroll(m_Output,x.Message);
			}
		}

		private void OnParserError(Core.Token token, string message)
		{
			WriteAndScroll(m_Output,message);
		}

		/// <summary>
		///		UI command to exit IDE.
		/// </summary>
		private void OnExit(object sender, EventArgs e)
		{
			Close();
		}
				
		/// <summary>
		///		UI command to create new project.
		/// </summary>
		private void OnNewProject(object sender, EventArgs e)
		{
			NewProjectWizard wizard = new NewProjectWizard();
			if(wizard.ShowDialog() != DialogResult.OK)
				return;
			LoadProject(Project.Create(wizard.ProjectPath + "\\" + wizard.ProjectName + ".shp",wizard.ProjectName));
			UpdateUIState();
		}

		/// <summary>
		///		UI command to open a project.
		/// </summary>
		private void OnOpenProject(object sender, EventArgs e)
		{
			OpenFileDialog browser = new OpenFileDialog();
			browser.Filter = "Sharp Project|*.shp";
			browser.CheckFileExists = true;
			if(browser.ShowDialog() != DialogResult.OK)
				return;
			LoadProject(Project.Open(browser.FileName));
			UpdateUIState();
		}

		/// <summary>
		///  UI command to close opened project.
		/// </summary>
		private void OnCloseProject(object sender, EventArgs e)
		{
			CloseProject();
			UpdateUIState();
		}

		/// <summary>
		///		UI command to add a existing file to the opened project.
		/// </summary>
		private void OnAddFile(object sender, EventArgs e)
		{
			OpenFileDialog browser = new OpenFileDialog();
			browser.Filter = "Sharp Source File|*.sh";
			browser.CheckFileExists = true;
			if(browser.ShowDialog() != DialogResult.OK)
				return;
			foreach(ProjectFile file in m_Project.ProjectFiles)
			{
				if(file.Path == browser.FileName)
				{
					MessageBox.Show("File is already part of the project.");
					return;
				}
			}
			m_Project.ProjectFiles.Add(new ProjectFile(m_Project,browser.FileName));
			UpdateUIState();
		}

		/// <summary>
		///		UI command to create a new file and add it to the opened project.
		/// </summary>
		private void OnNewFile(object sender, EventArgs e)
		{
			NewFileWizard wizard = new NewFileWizard(m_Project);
			if(wizard.ShowDialog() != DialogResult.OK)
				return;
			m_Project.ProjectFiles.Add(wizard.ProjectFile);
			UpdateUIState();
		}

		/// <summary>
		///		UI command to drop down the tools menu.
		/// </summary>
		private void OnToolsMenuDropDown(object sender, EventArgs e)
		{
			m_BuildParseTree.Enabled = m_BuildSyntaxTree.Enabled = (m_ProjectFile != null);
		}

		/// <summary>
		///		UI command to drop down the project menu.
		/// </summary>
		private void OnProjectMenuDropDown(object sender, EventArgs e)
		{
			TreeNode selected = m_tvProjectExplorer.SelectedNode;
			if(selected == null)
				return;
			Debug.Assert(selected.Tag != null,"Tree node has no tag value.");
			if(selected.Tag.GetType() == typeof(ProjectFile))
			{
				ProjectFile file = selected.Tag as ProjectFile;
				
				m_RemoveFile.Enabled = m_DeleteFile.Enabled = true;
				m_RemoveFile.Text = "&Remove " + file.Name;
				m_DeleteFile.Text = "&Delete " + file.Name;
			}
			else
			{
				m_RemoveFile.Enabled = m_DeleteFile.Enabled = false;
				m_RemoveFile.Text = "&Remove File";
				m_DeleteFile.Text = "&Delete File";
			}
		}

		/// <summary>
		///		UI command to remove a file from the opened project.
		/// </summary>
		private void OnRemoveFile(object sender, EventArgs e)
		{
			TreeNode selected = m_tvProjectExplorer.SelectedNode;
			if(selected == null)
				return;
			Debug.Assert(selected.Tag != null,"Tree node has no tag value.");
			if(selected.Tag.GetType() == typeof(ProjectFile))
			{
				ProjectFile file = selected.Tag as ProjectFile;
				m_Project.ProjectFiles.Remove(file);
				if(m_ProjectFiles.Contains(file))
					m_ProjectFiles.Remove(file);
			}
		}

		/// <summary>
		///		UI command to remove and delete a file from the opened project.
		/// </summary>
		private void OnDeleteFile(object sender, EventArgs e)
		{
			TreeNode selected = m_tvProjectExplorer.SelectedNode;
			if(selected == null)
				return;
			Debug.Assert(selected.Tag != null,"Tree node has no tag value.");
			if(selected.Tag.GetType() == typeof(ProjectFile))
			{
				ProjectFile file = selected.Tag as ProjectFile;
				m_Project.ProjectFiles.Remove(file);
				if(m_ProjectFiles.Contains(file))
				{
					m_ProjectFiles.Remove(file);
					File.Delete(file.Path);
					file = null;
				}
			}
		}

		/// <summary>
		///		UI command to save current file.
		/// </summary>
		private void OnSaveFile(object sender, EventArgs e)
		{
			m_ProjectFile.Source.SaveFile(m_ProjectFile.Path);
			m_ProjectFile.IsChanged = false;
		}

		/// <summary>
		///		UI command to save all opened files.
		/// </summary>
		private void OnSaveAllFiles(object sender, EventArgs e)
		{
			foreach(ProjectFile file in m_ProjectFiles)
			{
				file.Source.SaveFile(file.Path);
				file.IsChanged = false;
			}
		}


		/// <summary>
		///		UI command to open a project file for editing.
		/// </summary>
		private void OnProjectExplorerDoubleClick(object sender, EventArgs e)
		{
			TreeNode selected = m_tvProjectExplorer.SelectedNode;
			if(selected == null)
				return;
			Debug.Assert(selected.Tag != null,"Tree node has no tag value.");
			if(selected.Tag.GetType() == typeof(ProjectFile))
			{
				ProjectFile file = selected.Tag as ProjectFile;
				if(!m_ProjectFiles.Contains(file))
					m_ProjectFiles.Add(file);
				else
				{
					Crownwood.Magic.Controls.TabPage tabPage = file.Tab;
					m_Files.SelectedTab = tabPage;
				}
			}			
		}

		/// <summary>
		///		UI command to close a file.
		/// </summary>
		private void OnFilesClosed(object sender, EventArgs e)
		{
			if(m_Files.TabPages.Count == 0)
				return;
			m_ProjectFiles.Remove(m_Files.SelectedTab.Tag as ProjectFile);
		}


		/// <summary>
		///		UI command that modified the source code of a file.
		/// </summary>
		private void OnProjectFileTextChanged(object sender, EventArgs e)
		{
			ProjectFile file = ((TextAreaControl)sender).Tag as ProjectFile;
			file.IsChanged = true;
		}

		/// <summary>
		///		UI command that displayed a new source tab page.
		/// </summary>
		private void OnPageGotFocus(object sender, EventArgs e)
		{
			m_ProjectFile = m_Files.SelectedTab.Tag as ProjectFile;
			UpdateUIState();
		}

		/// <summary>
		///		UI command to build the parse tree for the current file.
		/// </summary>
		private void OnBuildParseTree(object sender, EventArgs e)
		{
			if(m_ProjectFile == null)
				return;

			m_ProjectFile.Source.SaveFile(m_ProjectFile.Path);
			m_ProjectFile.IsChanged = false;

			Scanner scanner = new Scanner(m_ProjectFile.Path,m_Language);
			Parser parser = new Parser(scanner,m_Language);

			ParseTreeNode root = parser.CreateParseTree ();

			if(root == null)
			{
				UI.Error("Cannot build parse tree from file [" + m_ProjectFile.Name + "] because its not grammatical");
				return;
			}

			//
			// Show parse tree
			//

			m_tvParseTree.Nodes.Clear();
			TreeNode rootNode = new TreeNode(root.Name,(int)IconIndex.NonTerminal,(int)IconIndex.NonTerminal);
			BuildParseTreeNode(rootNode,root.Children);
			m_tvParseTree.Nodes.Add(rootNode);
		}

		private void BuildParseTreeNode(TreeNode parent, ParseTreeNode [] children)
		{
			if(children == null)
				return;
			foreach(ParseTreeNode child in children)
			{

				TreeNode node = new TreeNode(child.Name);
				node.SelectedImageIndex = node.ImageIndex = child.Children == null ? (int)IconIndex.Terminal : (int)IconIndex.NonTerminal;
				if(child.Children != null)
					BuildParseTreeNode(node,child.Children);
				parent.Nodes.Add(node);
			}
		}

		/// <summary>
		///		UI command to build the parse tree for the current file.
		/// </summary>
		private void OnBuildSyntaxTree(object sender, EventArgs e)
		{
			if(m_ProjectFile == null)
				return;

			m_ProjectFile.Source.SaveFile(m_ProjectFile.Path);
			m_ProjectFile.IsChanged = false;

			Scanner scanner = new Scanner(m_ProjectFile.Path,m_Language);
			Parser parser = new Parser(scanner,m_Language);

			parser.Error += new ParserEventHandler(OnError);

			Module module = parser.CreateSyntaxTree();

			if(module == null)
			{
				UI.Error("Cannot build syntax tree from file [" + m_ProjectFile.Name + "] because its not grammatical");
				return;
			}

			//
			// Show parse tree
			//

			m_tvSyntaxTree.Nodes.Clear();
			TreeNode rootNode = new TreeNode("Syntax Tree",(int)IconIndex.Parse_Tree,(int)IconIndex.Parse_Tree);
			BuildSyntaxTreeNode(rootNode,module);
			m_tvSyntaxTree.Nodes.Add(rootNode);
		}

		private void BuildSyntaxTreeNode(TreeNode parent, object node)
		{
			if(node == null)
				return;

			if(node.GetType() == typeof(Module))
			{
				Module module = (Module)node;

				TreeNode moduleNode = new TreeNode("Module : " + module.Name,(int)IconIndex.Module,(int)IconIndex.Module);
				BuildSyntaxTreeNode(moduleNode,module.Body);
				parent.Nodes.Add(moduleNode);
			}
			else if(node.GetType() == typeof(Body))
			{
				Body body = (Body)node;
				TreeNode bodyNode = new TreeNode("Body",(int)IconIndex.Body,(int)IconIndex.Body);
				if(body.Structures != null)
					foreach(Structure structure in body.Structures)
						BuildSyntaxTreeNode(bodyNode,structure);
				if(body.Functions != null)
					foreach(Function function in body.Functions)
						BuildSyntaxTreeNode(bodyNode,function);
				if(body.Statements != null)
					foreach(Statement statement in body.Statements)
						BuildSyntaxTreeNode(bodyNode,statement);
				parent.Nodes.Add(bodyNode);
			}
			else if(node.GetType() == typeof(Function))
			{
				Function function = (Function)node;
				TreeNode functionNode = new TreeNode("Function : " + function.Name,(int)IconIndex.Function,(int)IconIndex.Function);
				BuildSyntaxTreeNode(functionNode,function.Type);
				TreeNode parametersNode = new TreeNode("Parameters",(int)IconIndex.Expression,(int)IconIndex.Expression);
				if(function.Parameters != null)
					foreach(Parameter parameter in function.Parameters)
						BuildSyntaxTreeNode(parametersNode,parameter);
				functionNode.Nodes.Add(parametersNode);
				BuildSyntaxTreeNode(functionNode,function.Body);
				parent.Nodes.Add(functionNode);
			}
			else if(node.GetType() == typeof(Variable))
			{
				Variable variable = (Variable)node;
				TreeNode variableNode = new TreeNode("Variable : " + variable.Name,(int)IconIndex.Variable,(int)IconIndex.Variable);
				BuildSyntaxTreeNode(variableNode,variable.Type);
				TreeNode valueNode = new TreeNode("Value",7,7);
				BuildSyntaxTreeNode(valueNode,variable.Value);
				variableNode.Nodes.Add(valueNode);
				parent.Nodes.Add(variableNode);
			}
			else if(node.GetType() == typeof(Structure))
			{
				Structure structure = (Structure)node;
				TreeNode structureNode = new TreeNode("Structure : " + structure.Name,(int)IconIndex.Structure,(int)IconIndex.Structure);
				TreeNode variablesNode = new TreeNode("Variables",7,7);
				if(structure.Variables != null)
					foreach(Variable variable in structure.Variables)
						BuildSyntaxTreeNode(variablesNode,variable);
				structureNode.Nodes.Add(variablesNode);
				parent.Nodes.Add(structureNode);
			}
			else if(node.GetType() == typeof(Core.Type))
			{
				Core.Type type = (Core.Type)node;
				TreeNode typeNode = new TreeNode("Type",7,7);
				typeNode.Nodes.Add(new TreeNode("Primitive Type : " + type.PrimitiveType.ToString(),7,7));
				typeNode.Nodes.Add(new TreeNode("Variable Type : " + type.VariableType.ToString(),7,7));
				parent.Nodes.Add(typeNode);
			}
			else if(node.GetType() == typeof(Parameter))
			{
				Parameter parameter = (Parameter)node;
				TreeNode parameterNode = new TreeNode("Parameter : " + parameter.Name,7,7);
				BuildSyntaxTreeNode(parameterNode,parameter.Type);
				parameterNode.Nodes.Add(new TreeNode("Pass Method : " + parameter.PassMethod.ToString(),7,7));
				parent.Nodes.Add(parameterNode);
			}
			else if(node.GetType() == typeof(Assignment))
			{
				Assignment assignment = (Assignment)node;
				TreeNode assignmentNode = new TreeNode("Assignment : " + assignment.Name,(int)IconIndex.Expression,(int)IconIndex.Expression);
				TreeNode val = new TreeNode("Value",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(val,assignment.Value);
				assignmentNode.Nodes.Add(val);
				parent.Nodes.Add(assignmentNode);
			}
			else if(node.GetType() == typeof(If))
			{
				If ifStatement = (If)node;
				TreeNode ifNode = new TreeNode("if",7,7);
				TreeNode condition = new TreeNode("Condition",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(condition,ifStatement.Condition);
				TreeNode ifBody = new TreeNode("If Body",(int)IconIndex.Body,(int)IconIndex.Body);
				BuildSyntaxTreeNode(ifBody,ifStatement.IfBody);
				TreeNode elseBody = new TreeNode("Else Body",(int)IconIndex.Body,(int)IconIndex.Body);
				BuildSyntaxTreeNode(elseBody,ifStatement.ElseBody);
				ifNode.Nodes.Add(condition);
				ifNode.Nodes.Add(ifBody);
				ifNode.Nodes.Add(elseBody);
				parent.Nodes.Add(ifNode);
			}
			else if(node.GetType() == typeof(While))
			{
				While whileStatement = (While)node;
				TreeNode whileNode = new TreeNode("while",7,7);
				TreeNode condition = new TreeNode("Condition",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(condition,whileStatement.Condition);
				whileNode.Nodes.Add(condition);
				BuildSyntaxTreeNode(whileNode,whileStatement.Body);
				parent.Nodes.Add(whileNode);
			}
			else if(node.GetType() == typeof(Do))
			{
				Do doStatement = (Do)node;
				TreeNode doNode = new TreeNode("do",7,7);
				TreeNode condition = new TreeNode("Condition",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(condition,doStatement.Condition);
				doNode.Nodes.Add(condition);
				BuildSyntaxTreeNode(doNode,doStatement.Body);
				parent.Nodes.Add(doNode);
			}
			else if(node.GetType() == typeof(For))
			{
				For forStatement = (For)node;
				TreeNode forNode = new TreeNode("for",7,7);

				TreeNode initializer = new TreeNode("Initializer",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(initializer,forStatement.Initializer);
				forNode.Nodes.Add(initializer);

				TreeNode condition = new TreeNode("Condition",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(condition,forStatement.Condition);
				forNode.Nodes.Add(condition);

				TreeNode counter = new TreeNode("Counter",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(counter,forStatement.Counter);
				forNode.Nodes.Add(counter);

				BuildSyntaxTreeNode(forNode,forStatement.Body);
				parent.Nodes.Add(forNode);
			}
			else if(node.GetType() == typeof(BinaryExpression))
			{
				BinaryExpression binaryExpression = (BinaryExpression)node;
				TreeNode binaryExpressionNode = new TreeNode("Binary Expression : " + binaryExpression.BinaryOperatorType.ToString(),7,7);
				TreeNode left = new TreeNode("Left",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(left,binaryExpression.Left);

				TreeNode right = new TreeNode("Right",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(right,binaryExpression.Right);

				binaryExpressionNode.Nodes.Add(left);
				binaryExpressionNode.Nodes.Add(right);
				parent.Nodes.Add(binaryExpressionNode);
			}
			else if(node.GetType() == typeof(UnaryExpression))
			{
				UnaryExpression unaryExpression = (UnaryExpression)node;
				TreeNode unaryExpressionNode = new TreeNode("Unary Expression : " + unaryExpression.UnaryOperatorType.ToString(),7,7);
				
				TreeNode val = new TreeNode("Value",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(val,unaryExpression.Value);
				
				TreeNode indexer = new TreeNode("Indexer",(int)IconIndex.Expression,(int)IconIndex.Expression);
				BuildSyntaxTreeNode(indexer,unaryExpression.Indexer);

				unaryExpressionNode.Nodes.Add(val);
				unaryExpressionNode.Nodes.Add(indexer);
				parent.Nodes.Add(unaryExpressionNode);
			}	
			else if(node.GetType() == typeof(Literal))
			{
				Literal literal = (Literal)node;
				TreeNode literalNode = new TreeNode("Literal : " + literal.Value,(int)IconIndex.Expression,(int)IconIndex.Expression);
				TreeNode literalTypeNode = new TreeNode("Literal Type : " + literal.LiteralType.ToString(),7,7);
				literalNode.Nodes.Add(literalTypeNode);
				parent.Nodes.Add(literalNode);
			}
			else if(node.GetType() == typeof(Call))
			{
				Call call = (Call)node;
				TreeNode callNode = new TreeNode("Call : " + call.Name,(int)IconIndex.Function,(int)IconIndex.Function);
				TreeNode argumentsNode = new TreeNode("Arguments",7,7);
				if(call.Arguments != null)
					foreach(Argument argument in call.Arguments)
						BuildSyntaxTreeNode(argumentsNode,argument);
				callNode.Nodes.Add(argumentsNode);
				parent.Nodes.Add(callNode);
			}
			else if(node.GetType() == typeof(Name))
			{
				Name name = (Name)node;
				TreeNode nameNode = new TreeNode("Name : " + name.Value,(int)IconIndex.Expression,(int)IconIndex.Expression);
				parent.Nodes.Add(nameNode);
			}
			else if(node.GetType() == typeof(Argument))
			{
				Argument argument = (Argument)node;
				
				TreeNode argumentNode = new TreeNode("Argument",7,7);
				TreeNode valueNode = new TreeNode("Value",7,7);
				BuildSyntaxTreeNode(valueNode,argument.Value);

				argumentNode.Nodes.Add(valueNode);
				argumentNode.Nodes.Add(new TreeNode("Pass Method : " + argument.PassMethod.ToString(),7,7));
				parent.Nodes.Add(argumentNode);
			}
		}


		void OnError(Token token, string message)
		{
			WriteAndScroll(m_Output,"[" + token.Line + "," + token.Column + "] " + message + " : '" + token.Text + "'\n");
		}

		void OnWarning(Token token, string message)
		{

		}

		//
		// Events generated by the project.
		//

		/// <summary>
		///		Modify UI elements for the changed file.
		/// </summary>
		private void OnProjectFileChanged(ProjectFile file)
		{
			Crownwood.Magic.Controls.TabPage tabPage = file.Tab;
			
			if(file.IsChanged)
				tabPage.Title = file.Name + " *";
			else
				tabPage.Title = file.Name;
		}


		/// <summary>
		///		Add UI elements for the added file.
		/// </summary>
		private void OnProjectFileAdded(ProjectFile file)
		{
			TreeNode tnProject = (TreeNode)file.Project.Node;
			TreeNode tnFile = new TreeNode(Path.GetFileName(file.Path),(int)IconIndex.File,(int)IconIndex.File);
			tnFile.Tag = file;
			file.Node = tnFile;
			tnProject.Nodes.Add(tnFile);
			tnProject.Expand();
		}


		/// <summary>
		///		Remove UI elements for the removed file.
		/// </summary>
		private void OnProjectFileRemoved(ProjectFile file)
		{
			TreeNode tnFile = file.Node;
			tnFile.Remove();
		}

		/// <summary>
		///		Add UI elements for the file to be opened for editing.
		/// </summary>
		private void OnProjectFileOpened(ProjectFile file)
		{
			if(!File.Exists(file.Path))
			{
				MessageBox.Show("File not found.");
				return;
			}

			Crownwood.Magic.Controls.TabPage tabPage = new Crownwood.Magic.Controls.TabPage(file.Name);
			TextAreaControl editor = new ICSharpCode.TextEditor.TextAreaControl();
			editor.Tag = file;
			editor.LoadFile(file.Path);
			editor.Changed += new EventHandler(OnProjectFileTextChanged);
			tabPage.Control = editor;
			tabPage.Tag = file;
			tabPage.ImageList = m_ImageList;
			tabPage.ImageIndex = (int)IconIndex.File;
			file.Tab = tabPage;
			file.Source = editor;
			file.Changed += new ProjectFileEventHandler(OnProjectFileChanged);
			m_Files.TabPages.Add(tabPage);
			m_Files.SelectedTab = tabPage;
			file.IsChanged = false;

		}

		/// <summary>
		///		Remove UI elements for the file to be closed.
		/// </summary>
		private void OnProjectFileClosed(ProjectFile file)
		{
			m_Files.TabPages.Remove(file.Tab);

			file.Source = null;
			file.Tab = null;

			if(m_Files.SelectedTab != null)
				m_ProjectFile = m_Files.SelectedTab.Tag as ProjectFile;
			else
				m_ProjectFile = null;
			UpdateUIState();
		}
	}
}

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


Written By
Web Developer
United States United States
Currently a graduate student at UCI.

Comments and Discussions