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

Bird Programming Language: Part 1

, 1 Jan 2013 GPL3
A new general purpose language that aims to be fast, high level and simple to use.
Bird-noexe.zip
Bird
Archives
crt2.o
crtbegin.o
crtend.o
libadvapi32.a
libcomctl32.a
libcomdlg32.a
libgcc.a
libgdi32.a
libglu32.a
libkernel32.a
libmingw32.a
libmingwex.a
libmoldname.a
libmsvcrt.a
libopengl32.a
libshell32.a
libstdc++.a
libuser32.a
libwinmm.a
libwsock32.a
Libraries
BirdCore
Array.bird
BigInteger.bird
BinaryRW.bird
BirdCore.a
BirdCore.blib
CategoryData.dat
Console.bird
Convert.bird
Debug.bird
Entry.bird
Environment.bird
Exception.bird
Float.bird
LEB128.bird
Math.bird
Memory.bird
Object.bird
Random.bird
Reflection.bird
StandardC.bird
Stream.bird
String.bird
ToLowerData.dat
ToUpperData.dat
Types.bird
ValueType.bird
Win32.bird
x86Helper.bird
BlitzMax
.bmx
Launcher.bmx.gui.release.win32.x86.o
appstub.release.win32.x86.a
bank.release.win32.x86.a
bankstream.release.win32.x86.a
blitz.release.win32.x86.a
BlitzMax.a
BlitzMax.bird
BlitzMax.blib
d3d7max2d.release.win32.x86.a
d3d9max2d.release.win32.x86.a
directx.release.win32.x86.a
dxgraphics.release.win32.x86.a
event.release.win32.x86.a
filesystem.release.win32.x86.a
font.release.win32.x86.a
glgraphics.release.win32.x86.a
glmax2d.release.win32.x86.a
graphics.release.win32.x86.a
hook.release.win32.x86.a
keycodes.release.win32.x86.a
Launcher.bmx
libpng.release.win32.x86.a
linkedlist.release.win32.x86.a
math.release.win32.x86.a
max2d.release.win32.x86.a
opengl.release.win32.x86.a
pixmap.release.win32.x86.a
pngloader.release.win32.x86.a
polledinput.release.win32.x86.a
standardio.release.win32.x86.a
stdc.release.win32.x86.a
stream.release.win32.x86.a
system.release.win32.x86.a
textstream.release.win32.x86.a
win32.release.win32.x86.a
zlib.release.win32.x86.a
PrgLinec.bmx
Samples
Circles
Circles.bird
CppMain.bird
Fire
Fire.bird
Higher Order Functions
C#
Higher Order Functions.v11.suo
Properties
Test.bird
msvcrt.lib
Reflection
Reflection.bird
Squares
Squares.bird
Template
Template.bird
Source
Base
Bird.v11.suo
Expressions
Identifiers
Languages
NativeCode
Properties
Recognizers
Expressions
Scopes
x86
Thumbs.db
Bird.zip
crt2.o
crtbegin.o
crtend.o
libadvapi32.a
libcomctl32.a
libcomdlg32.a
libgcc.a
libgdi32.a
libglu32.a
libkernel32.a
libmingw32.a
libmingwex.a
libmoldname.a
libmsvcrt.a
libopengl32.a
libshell32.a
libstdc++.a
libuser32.a
libwinmm.a
libwsock32.a
Binaries
ar.exe
Bird.exe
fasm.exe
ld.exe
libiconv-2.dll
libintl-8.dll
Array.bird
BigInteger.bird
BinaryRW.bird
BirdCore.a
BirdCore.blib
CategoryData.dat
Console.bird
Convert.bird
Debug.bird
Entry.bird
Environment.bird
Exception.bird
Float.bird
LEB128.bird
Math.bird
Memory.bird
Object.bird
Random.bird
Reflection.bird
StandardC.bird
Stream.bird
String.bird
ToLowerData.dat
ToUpperData.dat
Types.bird
ValueType.bird
Win32.bird
x86Helper.bird
Launcher.bmx.gui.release.win32.x86.o
appstub.release.win32.x86.a
bank.release.win32.x86.a
bankstream.release.win32.x86.a
blitz.release.win32.x86.a
BlitzMax.a
BlitzMax.bird
BlitzMax.blib
d3d7max2d.release.win32.x86.a
d3d9max2d.release.win32.x86.a
directx.release.win32.x86.a
dxgraphics.release.win32.x86.a
event.release.win32.x86.a
filesystem.release.win32.x86.a
font.release.win32.x86.a
glgraphics.release.win32.x86.a
glmax2d.release.win32.x86.a
graphics.release.win32.x86.a
hook.release.win32.x86.a
keycodes.release.win32.x86.a
Launcher.bmx
libpng.release.win32.x86.a
linkedlist.release.win32.x86.a
math.release.win32.x86.a
max2d.release.win32.x86.a
opengl.release.win32.x86.a
pixmap.release.win32.x86.a
pngloader.release.win32.x86.a
polledinput.release.win32.x86.a
standardio.release.win32.x86.a
stdc.release.win32.x86.a
stream.release.win32.x86.a
system.release.win32.x86.a
textstream.release.win32.x86.a
win32.release.win32.x86.a
zlib.release.win32.x86.a
PrgLinec.bmx
PrgLinec.exe
Circles.bird
CppMain.bird
Fire.bird
Higher Order Functions.v11.suo
Test.bird
msvcrt.lib
Reflection.bird
Squares.bird
Template.bird
Bird.v11.suo
Thumbs.db
examples.zip
Examples
As.exe
AsLibs.a
PerfTest
Launcher.bmx
Squares
.bmx
Launcher.bmx
Template
Launcher.bmx
source.zip
Anonymus 7_1
Anonymus.csproj.user
Anonymus.idc
Anonymus.pidb
Anonymus.suo
Anonymus.userprefs
Base
Expressions
Lib
Long
LongDivTest.bmx
ULongConv.bmx
Math
MISZ
AsLibs.a
PerfTest
Launcher.bmx
Squares
Launcher.bmx
Template
Launcher.bmx
PrgLinec.bmx
PrgLinec.exe
Properties
Scopes
Txt
Asm.docx
Code.docx
Lib.aslib
~$Code.docx
x86
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Bird
{
	[Flags]
	public enum OnEnterLeaveResult : byte
	{
		Succeeded = 0,
		Failed = 1,
		Cancel = 2,
		EnterNew = 4,
		LeaveNew = 8,
		EnterLeaveNew = EnterNew | LeaveNew,
		FailedAndCancel = Failed | Cancel,
	}

	[Flags]
	public enum CodeContextFlags : byte
	{
		None = 0,
	}

	public enum JumpMode : byte
	{
		Enter,
		Leave,
	}

	[Flags]
	public enum CodeContextResult : byte
	{
		Succeeded = 0,
		Failed = 1,
		JumpedOut = 2,
	}

	public struct JumpDestination
	{
		public IdContainer Container;
		public JumpMode Mode;

		public JumpDestination(IdContainer Container, JumpMode Mode = JumpMode.Enter)
		{
			this.Container = Container;
			this.Mode = Mode;
		}
	}

	public abstract class CodeContext
	{
		public CodeContextFlags Flags;
		public IdContainer Container;
		public IdContainer ExitAfter;
		JumpDestination FinallyJump;

		public abstract CodeContext Copy();

		public virtual OnEnterLeaveResult OnEnterContainer()
		{
			var RetValue = OnEnterLeaveResult.Succeeded;

			if (Container is Command)
			{
				var Comm = Container as Command;
				var Type = Comm.Type;
				if (Type == CommandType.If)
				{
					for (var i = 0; i < Comm.Children.Count; i++)
					{
						if ((Copy(Comm.Children[i]).Process() & CodeContextResult.Failed) != 0)
							RetValue |= OnEnterLeaveResult.Failed;

						if (i == Comm.Expressions.Count) 
							return RetValue | OnEnterLeaveResult.Cancel;
					}
				}
				else if (Type == CommandType.Try)
				{
					if (Comm.CatchScope != null)
					{
						if ((Copy(Comm.CatchScope).Process() & CodeContextResult.Failed) != 0)
							RetValue |= OnEnterLeaveResult.Failed;
					}

					RetValue |= OnEnterLeaveResult.EnterNew;
					Container = Comm.Children[0];
				}
				else if (Commands.IsJumpCommand(Type))
				{
					return RetValue | Jump(Comm.GetJumpDestination());
				}
				else if (Commands.IsLoopCommand(Type))
				{
					var Res = Comm.WillRun;
					if (Res != ConditionResult.False)
					{
						if (Res == ConditionResult.True)
						{
							Container = Comm.Children[0];
							RetValue |= OnEnterLeaveResult.EnterNew;
						}
						else
						{
							if ((Copy(Comm.Children[0]).Process() & CodeContextResult.Failed) != 0)
								RetValue |= OnEnterLeaveResult.Failed;
						}
					}
				}
				else if (Type == CommandType.Throw || Type == CommandType.Rethrow)
				{
					return OnEnterLeaveResult.Cancel;
				}
			}
			else if (Container is CodeScopeNode)
			{
				if (Container.Children.Count > 0)
				{
					Container = Container.Children[0];
					RetValue |= OnEnterLeaveResult.EnterNew;
				}
			}

			return RetValue;
		}

		public virtual OnEnterLeaveResult OnLeaveContainer()
		{
			if (Container is FunctionScope)
			{
				return OnEnterLeaveResult.Cancel;
			}
			else if (Container.Parent is Command)
			{
				var ParentComm = Container.Parent as Command;
				if (ParentComm.Type == CommandType.Try)
				{
					if (ParentComm.FinallyScope != Container && ParentComm.FinallyScope != null)
					{
						Container = ParentComm.FinallyScope;
						return OnEnterLeaveResult.EnterNew;
					}

					if (ParentComm.FinallyScope == Container && FinallyJump.Container != null)
						return Jump(FinallyJump);
				}
			}
			else if (Container.Parent is CodeScopeNode)
			{
				var Scope = Container.Parent as CodeScopeNode;
				var NewCommPos = Scope.GetChildIndex(Container) + 1;

				if (NewCommPos < Scope.Children.Count)
				{
					Container = Scope.Children[NewCommPos];
					return OnEnterLeaveResult.EnterNew;
				}
			}

			return OnEnterLeaveResult.Succeeded;
		}

		public CompilerState State
		{
			get { return Container.State; }
		}

		public CodeContext Copy(IdContainer Container)
		{
			var Ret = Copy();
			Ret.Container = Container;
			Ret.Flags = Flags;
			return Ret;
		}

		public CodeContext(IdContainer Container)
		{
			this.Container = Container;
		}

		public bool IsOutsideOfExitAfter
		{
			get
			{
				var E = ExitAfter;
				return E != null && !(Container == E || Container.IsSubContainerOf(E));
			}
		}

		public CodeContextResult Process(IdContainer Container)
		{
			var OldExitAfter = ExitAfter;
			var OldContainer = Container;

			this.Container = Container;
			this.ExitAfter = Container;

			var Res = Process();
			this.Container = OldContainer;
			this.ExitAfter = OldExitAfter;
			return Res;
		}

		public CodeContextResult Process()
		{
			var RetValue = CodeContextResult.Succeeded;
			var State = Container.State;

			while (true)
			{
				var Result = OnEnterContainer();
				if ((Result & OnEnterLeaveResult.Failed) != 0) RetValue |= CodeContextResult.Failed;
				if ((Result & OnEnterLeaveResult.Cancel) != 0) return RetValue;

				if ((Result & OnEnterLeaveResult.EnterLeaveNew) != 0)
				{
					if (IsOutsideOfExitAfter) return RetValue | CodeContextResult.JumpedOut;
					if ((Result & OnEnterLeaveResult.EnterNew) != 0) continue;
				}

				while (true)
				{
                    var OldContainer = Container;
					var LResult = OnLeaveContainer();
					if ((LResult & OnEnterLeaveResult.Failed) != 0) RetValue |= CodeContextResult.Failed;
					if ((LResult & OnEnterLeaveResult.Cancel) != 0) return RetValue;

					if ((LResult & OnEnterLeaveResult.EnterLeaveNew) != 0)
					{
						if (IsOutsideOfExitAfter) return RetValue | CodeContextResult.JumpedOut;
						if ((LResult & OnEnterLeaveResult.EnterNew) != 0) break;
						if ((LResult & OnEnterLeaveResult.LeaveNew) != 0) continue;
					}
                    else
                    {
                        if (OldContainer == ExitAfter) return RetValue;
                    }

					Container = Container.Parent;
				}
			}
		}

		public OnEnterLeaveResult Jump(JumpDestination JumpDst)
		{
			return Jump(JumpDst.Container, JumpDst.Mode);
		}

		public OnEnterLeaveResult Jump(IdContainer JumpTo, JumpMode Mode = JumpMode.Enter)
		{
			var Common = Container.GetCommonContainer(JumpTo);
			var TryComm = Container.GetParent<Command>(x =>
					x.Type == CommandType.Try && x.FinallyScope != null, Common);

			if (TryComm != null)
			{
				Container = TryComm.FinallyScope;
				FinallyJump = new JumpDestination(JumpTo, Mode);
				return OnEnterLeaveResult.EnterNew;
			}
			else
			{
				Container = JumpTo;
				if (Mode == JumpMode.Enter) return OnEnterLeaveResult.EnterNew;
				else if (Mode == JumpMode.Leave) return OnEnterLeaveResult.LeaveNew;
				else throw new ArgumentOutOfRangeException("Mode");
			}
		}
	}

	public struct CodeCheckerRouteData
	{
		public bool Assigned;
	}

	[Flags]
	public enum CodeCheckerIdDataFlags : byte
	{
		Read = 1,
		Used = 2,
		AddressUsed = 4,
	}

	public struct CodeCheckerIdData
	{
		public CodeCheckerIdDataFlags Flags;
	}

	public sealed class CodeCheckerContext : CodeContext
	{
		public CodeCheckerRouteData[] RouteData;
		public CodeCheckerIdData[] IdData;

		public CodeCheckerContext(IdContainer Container, CodeCheckerIdData[] IdData = null)
			: base(Container)
		{
			var FS = Container.FunctionScope;
			var IdCount = FS.LocalIdentifiers.Count;

			if (IdData == null)
			{
				IdData = new CodeCheckerIdData[IdCount];
				for (var i = 0; i < IdCount; i++)
				{
					if (FS.LocalIdentifiers[i].Used)
						IdData[i].Flags |= CodeCheckerIdDataFlags.Used;
				}
			}

			this.IdData = IdData;
			RouteData = new CodeCheckerRouteData[IdCount];
		}

		public bool VerifyAssigned(Identifier Id, CodeString Code)
		{
			if (!RouteData[Id.LocalIndex].Assigned)
			{
				var Local = Id as LocalVariable;
				if (Local != null && (!Local.PreAssigned))
				{
					State.Messages.Add(MessageId.UnassignedVar, Code);
					return false;
				}
			}

			return true;
		}

		public bool ProcessExpression(ExpressionNode Expr)
		{
			var D = Expr.Data.Get<NodeVariables>();
			for (var i = 0; i < D.AssignedIds.Count; i++)
			{
				var Id = D.AssignedIds[i].Identifier;
				if (Id.LocalIndex != -1)
				{
					RouteData[Id.LocalIndex].Assigned = true;
					IdData[Id.LocalIndex].Flags |= CodeCheckerIdDataFlags.Used;
				}
			}

			for (var i = 0; i < D.UsedBeforeAssignIds.Count; i++)
			{
				var Node = D.UsedBeforeAssignIds[i];
				var Id = Node.Identifier;

				if (Id.LocalIndex != -1)
				{
					IdData[Id.LocalIndex].Flags |= CodeCheckerIdDataFlags.Read;
					IdData[Id.LocalIndex].Flags |= CodeCheckerIdDataFlags.Used;
					if (!VerifyAssigned(Id, Node.Code)) return false;
				}
			}

			for (var i = 0; i < D.AddressUsed.Count; i++)
			{
				var Id = D.AddressUsed[i].Identifier;
				if (Id.LocalIndex != -1)
				{
					RouteData[Id.LocalIndex].Assigned = true;
					IdData[Id.LocalIndex].Flags |= CodeCheckerIdDataFlags.Used;
					IdData[Id.LocalIndex].Flags |= CodeCheckerIdDataFlags.AddressUsed;
				}
			}

			return true;
		}

		public override CodeContext Copy()
		{
			var Ret = new CodeCheckerContext(Container, IdData);
			Ret.RouteData = new CodeCheckerRouteData[RouteData.Length];
			RouteData.CopyTo(Ret.RouteData, 0);
			return Ret;
		}

		public void ResetOutside(IdContainer Container)
		{
			var FS = Container.FunctionScope;
			for (var i = 0; i < RouteData.Length; i++)
				if (RouteData[i].Assigned)
				{
					var C = FS.LocalIdentifiers[i].Container;
					if (C != Container && !Container.IsSubContainerOf(C))
					{
						RouteData[i].Assigned = false;
						i--;
					}
				}
		}

		public override OnEnterLeaveResult OnEnterContainer()
		{
			var RetValue = OnEnterLeaveResult.Succeeded;
			ResetOutside(Container);

			if (Container is Command)
			{
				var Comm = Container as Command;
				if ((Comm.Flags & CommandFlags.Unreachable) == 0)
					return OnEnterLeaveResult.Cancel;

				var Type = Comm.Type;
				Comm.Flags &= ~CommandFlags.Unreachable;

				if (Commands.IsJumpCommand(Type))
				{
					var Result = true;
					Comm.ForEachJumpedOver<CodeScopeNode>(x =>
					{
						var Cx = x.Parent as Command;
						if (Cx != null && Cx.Type == CommandType.Try && Cx.FinallyScope == x)
						{
							State.Messages.Add(MessageId.CannotLeaveFinally, Comm.Code);
							Result = false;
						}
					});

					if (!Result)
						return OnEnterLeaveResult.FailedAndCancel;
				}

				if (Type == CommandType.If)
				{
					for (var i = 0; i < Comm.Children.Count; i++)
					{
						var Chi = Comm.Children[i];
						if (i < Comm.Expressions.Count)
						{
							if (!ProcessExpression(Comm.Expressions[i]))
								RetValue |= OnEnterLeaveResult.Failed;

							if ((Copy(Chi).Process() & CodeContextResult.Failed) != 0)
								RetValue |= OnEnterLeaveResult.Failed;
						}
						else
						{
							if ((Copy(Chi).Process() & CodeContextResult.Failed) != 0)
								RetValue |= OnEnterLeaveResult.Failed;

							RetValue |= OnEnterLeaveResult.Cancel;
						}
					}

					return RetValue;
				}
				else if (Type == CommandType.Return)
				{
					if (Comm.Expressions != null && Comm.Expressions.Count > 0)
					{
						if (!ProcessExpression(Comm.Expressions[0]))
							RetValue |= OnEnterLeaveResult.Failed;
					}
				}
				else if (Type == CommandType.Expression)
				{
					if (!ProcessExpression(Comm.Expressions[0]))
						RetValue |= OnEnterLeaveResult.Failed;
				}
				else if (Type == CommandType.Throw || Type == CommandType.Rethrow)
				{
					if (!ProcessExpression(Comm.Expressions[0]))
						RetValue |= OnEnterLeaveResult.Failed;
				}
				else if (Type == CommandType.For)
				{
					if (!ProcessExpression(Comm.Expressions[0]))
						RetValue |= OnEnterLeaveResult.Failed;

					if (!ProcessExpression(Comm.Expressions[1]))
						RetValue |= OnEnterLeaveResult.Failed;
				}
				else if (Type == CommandType.While)
				{
					if (!ProcessExpression(Comm.Expressions[0]))
						RetValue |= OnEnterLeaveResult.Failed;
				}
			}

			return base.OnEnterContainer() | RetValue;
		}

		public override OnEnterLeaveResult OnLeaveContainer()
		{
			var RetValue = OnEnterLeaveResult.Succeeded;
			if (Container is Command)
			{
				var Comm = Container as Command;
				if (Comm.Type == CommandType.For)
				{
					if (!ProcessExpression(Comm.Expressions[2]))
						RetValue |= OnEnterLeaveResult.Failed;

					if (!ProcessExpression(Comm.Expressions[1]))
						RetValue |= OnEnterLeaveResult.Failed;
				}
				else if (Comm.Type == CommandType.DoWhile)
				{
					if (!ProcessExpression(Comm.Expressions[0]))
						RetValue |= OnEnterLeaveResult.Failed;
				}
			}

			Container.ForEachId(x =>
			{
				var R = x.TypeOfSelf.RealId as ReferenceType;
				if (R != null && R.Mode == ReferenceMode.IdGetsAssigned && !VerifyAssigned(x, x.Declaration))
					RetValue |= OnEnterLeaveResult.Failed;
			});

			return base.OnLeaveContainer() | RetValue;
		}
	}

	public static class CodeChecker
	{
		public static void Initialize(IdContainer Container)
		{
			if (Container is Command)
			{
				var Command = Container as Command;
				Command.Flags |= CommandFlags.Unreachable;
			}

			for (var i = 0; i < Container.Children.Count; i++)
				Initialize(Container.Children[i]);
		}

		public static CodeContextResult Process(FunctionScope Scope)
		{
			Initialize(Scope);
			var State = Scope.State;
			var Context = new CodeCheckerContext(Scope);
			var Ret = Context.Process();

			if (Scope.Code.Length > 0)
			{
				for (var i = 0; i < Context.IdData.Length; i++)
				{
					var Local = Scope.LocalIdentifiers[i] as LocalVariable;
					if (Local == null) continue;

					var IdData = Context.IdData[i];
					if ((IdData.Flags & CodeCheckerIdDataFlags.Used) == 0 &&
						(Local.Flags & IdentifierFlags.ReadOnly) == 0)
					{
						State.Messages.Add(MessageId.UnusedId, Local.Name);
					}
					else if ((IdData.Flags & CodeCheckerIdDataFlags.Read) == 0 &&
							(IdData.Flags & CodeCheckerIdDataFlags.AddressUsed) == 0 && !Local.PreAssigned)
					{
						State.Messages.Add(MessageId.AssignedButNeverUsed, Local.Name);
					}
				}
			}

			if ((Scope.ReturnLabelCommand.Flags & CommandFlags.Unreachable) == 0)
			{
				if (Scope.NeedsReturnVal)
				{
					Scope.State.Messages.Add(MessageId.NotAllPathReturn, Scope.Function.Declaration);
					Ret |= CodeContextResult.Failed;
				}
			}

			Scope.ReturnLabelCommand.Flags &= ~CommandFlags.Unreachable;
			if (!Finalize(Scope)) Ret |= CodeContextResult.Failed;
			return Ret;
		}

		public static bool Finalize(IdContainer Container, bool Unreachable = false)
		{
			var RetValue = true;
			var State = Container.State;

			if (Container is CodeScopeNode)
			{
				var Scope = Container as CodeScopeNode;
				for (var ChIndex = 0; ChIndex < Scope.Children.Count; ChIndex++)
				{
					var Ch = Scope.Children[ChIndex];
					if (Ch is Command)
					{
						var Comm = Ch as Command;
						if ((Comm.Flags & CommandFlags.Unreachable) != 0 && !Unreachable)
							State.Messages.Add(MessageId.UnreachableCode, Comm.Code);

						Unreachable = (Comm.Flags & CommandFlags.Unreachable) != 0;
					}

					Finalize(Ch, Unreachable);
				}
			}
			else if (Container is Command)
			{
				var Comm = Container as Command;
				for (var i = 0; i < Comm.Children.Count; i++)
				{
					if (!Finalize(Comm.Children[i], Unreachable))
						RetValue = false;
				}
			}
			else
			{
				throw new NotImplementedException();
			}

			return RetValue;
		}
	}
}

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, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

Dávid Kocsis
Student
Hungary Hungary
I've been programming for 8 years. My first big project was a remake of a nice bomberman game called Dyna Blaster. When i was little i played a lot with it. Now i'm working on a new programming language and code generator.
I would like to work with someone, so feel free to contact me about it.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411028.1 | Last Updated 1 Jan 2013
Article Copyright 2011 by Dávid Kocsis
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid