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

Bird Programming Language: Part 3

, 1 Jan 2013
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Bird.Recognizers
{
	public class TestScopeRecognizer : LanguageNode, IExprRecognizer
	{
		public TestScopeRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "testscope" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var Result = Code.StartsWith(Operators, Skip, new IdCharCheck(true));
			if (Result.Position != -1)
			{
				var State = Plugin.State;
				var Right = Code.Substring(Result.String.Length).Trim();
				Right = Right.TrimOneBracket(SkippingHandlers);

				if (Right.Length == 0)
				{
					State.Messages.Add(MessageId.DeficientExpr, Code);
					return ExprRecResult.Failed;
				}

				var Scope = new CodeScopeNode(Plugin.Container, Right);
				if (!Scope.ProcessCode()) return ExprRecResult.Failed;

				var List = Scope.GetContainerId("retvar", x => x is LocalVariable);
				var RetVar = Identifiers.SelectIdentifier(State, List, Code) as LocalVariable;
				if (RetVar == null) return ExprRecResult.Failed;

				Out = new ScopeExpressionNode(Scope, Code)
				{
					ReturnVar = RetVar,
				};

				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class CheckedUncExprRecognizer : LanguageNode, IExprRecognizer
	{
		public CheckedUncExprRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "checked", "unchecked" };
			NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var Result = Code.StartsWith(Operators, Skip, new IdCharCheck(true));
			if (Result.Position != -1)
			{
				var State = Plugin.State;
				var Right = Code.Substring(Result.String.Length).Trim();
				Right = Right.TrimOneBracket(SkippingHandlers);

				if (Right.Length == 0)
				{
					State.Messages.Add(MessageId.DeficientExpr, Code);
					return ExprRecResult.Failed;
				}

				var TypeMngrPlugin = Plugin.GetPlugin<TypeMngrPlugin>();
				if (TypeMngrPlugin == null) return ExprRecResult.Unknown;

				var OldCheckingMode = TypeMngrPlugin.CheckingMode;
				if (Result.Index == 0) TypeMngrPlugin.CheckingMode = CheckingMode.Checked;
				else if (Result.Index == 1) TypeMngrPlugin.CheckingMode = CheckingMode.Unchecked;
				else throw new ApplicationException();

				Out = Expressions.Recognize(Right, Plugin);
				TypeMngrPlugin.CheckingMode = OldCheckingMode;

				if (Out == null) return ExprRecResult.Failed;
				else return ExprRecResult.Ready;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class SimpleArgRecognizer : LanguageNode, IParameterRecognizer
	{
		public SimpleArgRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "," };
			NewLineLeft = NewLineRight = Operators;
		}

		public CodeString[] SplitToParameters(CompilerState State, CodeString Self, bool EnableMessages = true)
		{
			return RecognizerHelper.SplitToParameters(State, Self, ',', EnableMessages);
		}
	}

	public class GenericRecognizer : LanguageNode, IGenericRecognizer
	{
		public GenericRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = new string[] { "<" };
			NewLineLeft = new string[] { "<", ">" };
		}

		public SimpleRecResult GetGenericParams(CompilerState State, ref CodeString Code, 
			 out CodeString[] Out, bool EnableMessages = true)
		{
			Out = null;
			if (Code.Length > 0 && Code[Code.Length - 1] == '>')
			{
				var BracketPos = Code.GetBracketPos(State, true);
				if (BracketPos == -1) return SimpleRecResult.Failed;

				var ParamStart = BracketPos + 1;
				var StrParams = Code.TrimmedSubstring(State, ParamStart, Code.Length - ParamStart - 1);
				if (!StrParams.IsValid) return SimpleRecResult.Failed;

				Out = RecognizerHelper.GetParamList(State, StrParams);
				if (Out == null) return SimpleRecResult.Failed;

				Code = Code.Substring(0, BracketPos).Trim();
			}

			return SimpleRecResult.Unknown;
		}

        public override void Init(LanguageInitData InitData)
		{
			base.Init(InitData);

            foreach (var e in Language.Root.GetObjects<RelEquRecognizer>())
				e.RecFlags |= RelEquRecognizerFlags.DisableOpposed;

			var ListDisableFind = new List<string>();
			var ListDisableSkip = new List<string>();
            foreach (var e in Language.Root.GetObjects<LogicalRecognizer>())
			{
				if (e.Operators != null) ListDisableFind.AddRange(e.Operators);
				if (e.Skip != null) ListDisableFind.AddRange(e.Skip);
			}

			var DisableFind = Helper.ToArrayWithoutSame(ListDisableFind);
			var DisableSkip = Helper.GetSkipList(DisableFind, ListDisableSkip);

            foreach (var e in Language.Root.GetObjects<BracketRecognizer>())
			{
				e.GenericBracketSkipOptions = new GenericBracketSkipOptions()
				{
					Enabled = true,
					DisableFind = DisableFind,
					DisableSkip = DisableSkip,
					SkippingHandlers = SkippingHandlers,
				};
			}
		}
	}

	public class BracketGroupRecognizer : LanguageNode, IGroupRecognizer
	{
		public char BracketLeft = '{';
		public char BracketRight = '}';

		public BracketGroupRecognizer(LanguageNode Parent, char BracketLeft = '{', char BracketRight = '}')
			: base(Parent)
		{
		}

		public static NodeGroup GetGroups(PluginRoot Plugin, CodeString Code, char BracketLeft = '{', char BracketRight = '}')
		{
			var Ret = new NodeGroup(Code);
			var State = Plugin.State;

			var List = RecognizerHelper.SplitToParameters(State, Code, ',');
			if (List == null) return null;

			for (var i = 0; i < List.Length; i++)
			{
				var Param = List[i];
				if (Param.Length > 1 && Param[0] == BracketLeft && Param[Param.Length] == BracketLeft)
				{
					Param = Param.Substring(1, Param.Length - 1).Trim();
					Ret.Children.Add(Expressions.GetGroups(Plugin, Param));
				}
				else
				{
					var Node = Expressions.Recognize(Param, Plugin);
					if (Node == null) return null;

					Ret.Children.Add(Node);
				}
			}

			return Ret;
		}

		public NodeGroup GetGroups(PluginRoot Plugin, CodeString Code)
		{
			return GetGroups(Plugin, Code, BracketLeft, BracketRight);
		}
	}

	public struct GenericBracketSkipOptions
	{
		public bool Enabled;
		public string[] DisableFind;
		public string[] DisableSkip;
		public IList<IResultSkippingHandler> SkippingHandlers;
	}

	public enum GenericBracketSkipMode : byte
	{
		Disabled,
		Enabled,
		IfNoLogicalOp,
	}

	public class BracketRecognizer : LanguageNode, IExprRecognizer, IIdRecognizer, IResultSkippingHandler
	{
		public GenericBracketSkipOptions GenericBracketSkipOptions;

		public BracketRecognizer(LanguageNode Parent, GenericBracketSkipOptions GenericBracketSkipMode = new GenericBracketSkipOptions())
			: base(Parent)
		{
			this.GenericBracketSkipOptions = GenericBracketSkipMode;
		}

		static bool Check(CompilerState State, CodeString Code)
		{
			if (Code[0] == '(' && Code.GetBracketPos(State)  == -1)
				return false;

            if (Code[0] == ')')
            {
                State.Messages.Add(MessageId.ZNumErr, Code.Substring(0, 1));
                return false;
            }

			var P = Code.Length - 1;
            if (Code[P] == '(')
            {
                State.Messages.Add(MessageId.ZNumErr, Code.Substring(P));
                return false;
            }

			if (Code[P] == ')' && Code.GetBracketPos(State, true) == -1)
				return false;

			return true;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (!Check(Plugin.State, Code)) return ExprRecResult.Failed;

			var NewCode = Code.TrimBrackets(Plugin.State);
			if (!NewCode.IsValid) return ExprRecResult.Failed;
			if (NewCode.Length == Code.Length) return ExprRecResult.Unknown;

			Ret = Expressions.Recognize(NewCode, Plugin, true);
			return Ret == null ? ExprRecResult.Failed : ExprRecResult.Ready;
		}

		public SimpleRecResult Recognize(IdContainer Container, CodeString Code, GetIdOptions Options, ref Identifier Ret)
		{
			if (!Check(Container.State, Code)) return SimpleRecResult.Failed;

			var NewCode = Code.TrimBrackets(Container.State);
			if (!NewCode.IsValid) return SimpleRecResult.Failed;
			if (NewCode.Length == Code.Length) return SimpleRecResult.Unknown;

			Ret = Identifiers.Recognize(Container, NewCode, Options);
			return Ret == null ? SimpleRecResult.Failed : SimpleRecResult.Succeeded;
		}

		SkippingHandlerResult SkipBracket(ref ResultSkippingManager RSM)
		{
			if (RSM.Back)
			{
				var NewString = RSM.String.Substring(0, RSM.Current + 1);
				var Pos = NewString.GetBracketPos(true, RSM.SkippingHandlers);
				if (Pos != -1) return new SkippingHandlerResult(Pos);
			}
			else
			{
				var NewString = RSM.String.Substring(RSM.Current);
				var Pos = NewString.GetBracketPos(false, RSM.SkippingHandlers);
				if (Pos != -1) return new SkippingHandlerResult(Pos + RSM.Current);
			}

			return new SkippingHandlerResult(-1);
		}

		public SkippingHandlerResult SkipResult(ref ResultSkippingManager RSM)
		{
			if (!RSM.DoNotSkipBrackets)
			{
				var Char = RSM.CurrentChar;
				if (GenericBracketSkipOptions.Enabled)
				{
					if ((Char == '<' && !RSM.Back) || (Char == '>' && RSM.Back))
					{
						var Result = SkipBracket(ref RSM);
						if (Result.Index == -1 || GenericBracketSkipOptions.DisableFind == null)
							return Result;

						var Substring = RSM.String.SubstringFromTo(RSM.Current + 1, Result.Index - 1);
						var FindRes = Substring.Find(GenericBracketSkipOptions.DisableFind, 
							GenericBracketSkipOptions.DisableSkip, false, new IdCharCheck(true),
							GenericBracketSkipOptions.SkippingHandlers);

						if (FindRes.Position == -1)
							return Result;
					}
				}

				if (Helper.GetBracket(Char, RSM.Back))
					return SkipBracket(ref RSM);
			}

			return new SkippingHandlerResult(-1);
		}
	}

	public class ExprIdRecognizer : LanguageNode, IExprRecognizer
	{
		public ExprIdRecognizer(LanguageNode Parent)
			: base(Parent)
		{
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.IsValidIdentifierName)
			{
				Ret = new StrExpressionNode(Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class RetValLessRecognizer : LanguageNode, IRetValLessRecognizer, ICallParamRecognizer
	{
		public IExprRecognizer[] RunBefore;
		CallRecognizer CallRecognizer;

		public RetValLessRecognizer(LanguageNode Parent, IExprRecognizer[] RunBefore = null)
			: base(Parent)
		{
			this.RunBefore = RunBefore;
		}

        public override void Init(LanguageInitData InitData)
		{
            CallRecognizer = Language.Root.GetObject<CallRecognizer>();
			base.Init(InitData);
		}

		public static int FindParamPosition(CompilerState State, StringSlice Code)
		{
			var Ok = false;
			var Handlers = State.Language.GlobalHandlers;
			var RSM = new ResultSkippingManager(Handlers, Code);

			var Language = State.Language;
			var LangRoot = Language.Root;
			var CastRecognizer = Language.Root.GetObject<CastRecognizer>(false);

			while (RSM.Loop())
			{
				var Pos = RSM.Current;
				var Chr = Code[Pos];
				if (!Helper.IsIdChar(Chr))
				{
					if (!Ok) continue;

					if (Chr == '(')
					{
						var Brackets = Code.Substring(Pos);
						if (CastRecognizer != null && CastRecognizer.IsCastString(State, Brackets))
							return Pos;

						if (Brackets.GetBracketPos(false, Handlers) == Brackets.Length - 1)
							return Pos;
					}
					else if (char.IsWhiteSpace(Chr))
					{
						// ambiguous: Print (Obj is object).ToString()
						var After = Code.Substring(Pos + 1).Trim();
						var AfterChr = After.Length > 0 ? After[0] : '\0';
						if (Helper.IsIdChar(AfterChr) || AfterChr == '(' || AfterChr == '[')
							return Pos;
					}

                    if (Code.SubstringEquals(Pos, LangRoot.OnlyRight, LangRoot.OnlyRightSkip,
                        false, new IdCharCheck(true)).Position != -1)
                    {
                        return Pos;
                    }

                    for (var i = 0; i < Language.ExprRecognizers.Length; i++)
					{
						var Rec = Language.ExprRecognizers[i] as SkippedBetweenRecognizer;
						if (Rec != null && Code.SubstringEquals(Pos, Rec.Operators, Rec.Skip).Index != -1)
							return Pos;
					}
				}
				else
				{
					Ok = true;
				}
			}

			return -1;
		}

		public bool GetParameters(CompilerState State, CodeString Code, out CodeString Function, out CodeString Parameters)
		{
			var Pos = FindParamPosition(State, Code.String);
			if (Pos != -1)
			{
				Function = Code.Substring(0, Pos).Trim();
				var Handlers = State.Language.GlobalHandlers;
				Parameters = Code.Substring(Pos).TrimOneBracket(Handlers);
			}
			else
			{
				Function = Code;
				Parameters = Code.Substring(Code.Length);
			}

			return true;
		}

		public ExpressionNode[] ProcessParameters(PluginRoot Plugin, CodeString Function, CodeString[] Parameters)
		{
			return CallRecognizer.ProcessParameters(Plugin, Function, Parameters);
		}

		public ExpressionNode[] ProcessParameters(PluginRoot Plugin, CodeString Function, CodeString Parameters)
		{
			return CallRecognizer.ProcessParameters(Plugin, Function, Parameters);
		}

		public ExpressionNode CreateFuncCallNode(PluginRoot Plugin, CodeString Code)
		{
			CodeString Function, Parameters;
			if (!GetParameters(Plugin.State, Code, out Function, out Parameters))
				return null;

			var Ch = CallRecognizer.ProcessParameters(Plugin, Function, Parameters);
			if (Ch == null) return null;

			return Plugin.NewNode(new OpExpressionNode(Operator.Call, Ch, Code));
		}

		public ExpressionNode Recognize(CodeString Code, PluginRoot Plugin)
		{
			ExpressionNode Out;
			var Res = Expressions.Recognize(Code, Plugin, RunBefore, out Out);
			if (Res == SimpleRecResult.Unknown) return CreateFuncCallNode(Plugin, Code);
			else return Res == SimpleRecResult.Succeeded ? Out : null;
		}
	}
}

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 | Mobile
Web01 | 2.8.140926.1 | Last Updated 1 Jan 2013
Article Copyright 2012 by Dávid Kocsis
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid