Click here to Skip to main content
15,882,163 members
Articles / High Performance Computing / Vectorization

Bird Programming Language: Part 1

Rate me:
Please Sign up or sign in to vote.
4.92/5 (129 votes)
1 Jan 2013GPL312 min read 373.6K   2.7K   153  
A new general purpose language that aims to be fast, high level and simple to use.
using System;
using System.Collections.Generic;
using System.Threading;
using System.IO;
using System.Globalization;
using System.Reflection;
using System.Linq;

namespace Bird
{
	public enum OperatingSystem : byte
	{
		Windows,
		Linux,
		MacOSX,
	}

	public class MessageStringsException : Exception
	{
		public string _Message;

		public override string Message
		{
			get { return _Message; }
		}

		public MessageStringsException(string Message)
		{
			this._Message = Message;
		}
	}

	public class MessageStrings
	{
		public Dictionary<string, string> Strings;

		public string this[string Key]
		{
			get { return Strings[Key]; }
		}

		public MessageStrings()
		{
			Process(CultureInfo.CurrentCulture);
		}

		public void Read(CultureInfo Culture)
		{
			var Name = Culture.TwoLetterISOLanguageName;
			var f = "Messages." + Name + ".txt";
			if (!File.Exists(f))
			{
				f = "Messages.en.txt";
				if (!File.Exists(f))
					throw new MessageStringsException("Can't find message file");
			}

			Read(f);
		}

		public void Read(string FileName)
		{
			var Stream = File.OpenRead(FileName);
			Read(Stream);
			Stream.Dispose();
		}

		public void Read(Stream Stream)
		{
			var Reader = new StreamReader(Stream);
			Process(Reader.ReadToEnd());
			Reader.Dispose();
		}

		public void Process(CultureInfo Culture)
		{
			var f = "Messages_" + Culture.TwoLetterISOLanguageName;
			var Ret = Resource.ResourceManager.GetString(f);
			if (Ret == null && (Ret = Resource.ResourceManager.GetString("Messages_en")) == null)
				throw new MessageStringsException("Can't find message file");

			Process(Ret);
		}

		public void Process(string String)
		{
			Strings = new Dictionary<string, string>();
			var Start = 0;
			var LineIndex = 0;

			for (var i = 0; i < String.Length; i++)
			{
				var Chr = String[i];
				if (Chr == '\n')
				{
					LineIndex++;
					var Line = String.Substring(Start, i - Start).Trim();
					ProcessLine(Line, LineIndex);
					Start = i + 1;
				}
			}
		}

		public void ProcessLine(string Line, int LineIndex)
		{
			if (Line.Length == 0 || Line.StartsWith("//") || Line.StartsWith("'"))
				return;

			var Pos = Line.IndexOf('=');
			if (Pos == -1) throw new MessageStringsException("Missing '=' at line " + LineIndex);

			var Key = Line.Substring(0, Pos).Trim();
			var Value = Line.Substring(Pos + 1).Trim();
			if (Key.Length == 0 || Value.Length == 0)
				throw new MessageStringsException("Missing key or value at line " + LineIndex);

			if (Value.Length < 2 || Value[0] != '\"' || Value[Value.Length - 1] != '\"')
				throw new MessageStringsException("Invalid value at line " + LineIndex);
			else Value = Value.Substring(1, Value.Length - 2);

			Strings.Add(Key, Value);
		}
	}

	public enum MessageSeverity : byte
	{
		Error = 0,
		Warning = 1,
		Info = 2
	}

	public enum MessageId
	{
		UnknownError = 1000,
		NoMacro,
		NotValidName,
		WrongParamList,
		MacroAlreadyDefined,
		NoParamName,
		ParamCount,
		NoEndif,
		UnknownType,
		WrongDefinition,
		// ConstStringErr,
		ZNumErr,
		ConstNumErr,
		UnknownOp,
		CantCall,
		MustBeConst,
		CannotConvert,
		InvalidScopeIndent,
		UnknownId,
		OpsInGblScope,
		NotExpected,
		PreprocError,
		TypeNotSpecified,
		IdAlreadyDefined,
		DeficientExpr,
		DeficientDoWhile,
		LoopWithoutDo,
		CantOpApplied,
		CallingNotFunc,
		MissingParam,
		MissingThen,
		AsmNotRId,
		NotAllPathReturn,
		AssignRValue,
		UnknownCommand,
		ImplicitlyCast,
		ForToDownToUntil,
		NoForVar,
		MoreForVar,
		NoForInitValue,
		NeedThenElse,
		WrongSettings,
		EntryNotFound,
		EntryNotSpecified,
		ImpExpGlbScope,
		CannotConvertConst,
		UnassignedVar,
		AddressOfRValue,
		MustBeGlobal,
		Untyped,
		CannotDeclVar,
		CantOpApplied2,
		UnknownType2,
		SameEnumValue,
		DefFuncParamVal,
		UnBreakCountinueable,
		CaseWithoutSwitch,
		CaseSystaxErr,
		SwitchNoCaseDef,
		SwitchAlreadyHasDef,
		EnumValOverflow,
		LabelAlreadyDefined,
		UnknownLabel,
		ConstOutOfRange,
		ReadOnly,
		CallConvErr,
		UntypedFunction,
		CannotInherit,
		TypeCannotBeSpecified,
		NoConstructor,
		CantDeclare,
		Static,
		NonStatic,
		ExternNonMSCoff,
		FuncCannotHaveInnerScope,
		CannotGetSize,
		MacroWithoutValue,
		VarFuncRetType,
		NonStaticInStaticClass,
		//SealedErr,
		//StaticSealed,
		CannotInheritStatic,
		CannotInheritSealed,
		NoParamLessConstructor,
		HasntGotMembers,
		CycleInStructured,
		MustBeUnnamed,
		UnassignedVar2,
		CannotBeThisType,
		MustBeNamed,
		MustHaveInitVal,
		FileDoesntExists,
		CantLoadFile,
		EnumTypeError,
		CantBeConst,
		ConstsCantBeStatic,
		CantUseConstructors,
		CannotCalcConst,
		GuidCannotUsed,
		InvalidGuidFormat,
		SameOverloads,
		AmbiguousReference,
		MoreAccessModifier,
		CantAccessPrivate,
		CantAccessProtected,
		PrivateInOtherLib,
		ProtPrivInNonStructured,
		OverrideVirtual,
		StructorFuncModifier,
		VirtualAbstractContainer,
		NoOverridable,
		OverrideNonvirtual,
		PrivateVirtual,
		MustBeInteger,
		OverrideSealed,
		NobaseError,
		NobaseClassbase,
		ArrayLengthTooSmall,
		ArrayLengthTooBig,
		ArrayDifferentTypes,
		ArrayInvalidType,
		WithMustBeStructured,
		InvalidCast,
		CantAccessInternal,
		MissingTypeParams,
		ReinterpretSize,
		ArrayInvalidLength,
		CharInvalidLength,
		InvalidOp,
		ReturnTypeNotTuple,
		RetVarAlreadySpecified,
		CannotDeclFunc,
		CannotReturn,
		IncompatibleMods,
		AbstractInner,
		AbstractInNonAbstract,
		StaticCallAbstract,
		LessAccessable,
		StructParamLessCtor,
		InvalidNumberOfIds,
		ClassMustBeAbstract,
		MultipleRadix,
		InvalidEscapeSequence,
		//QuotationMark,
		InvalidAddressType,
		ExprVarDeclInitVal,
		NoPropertyGetter,
		NoPropertySetter,
		UnaccessableGetter,
		UnaccessableSetter,
		PropertyAccessLevel,
		ModifierCantBeUsed,
		ModifierCantBeUsed2,
		EntryMustBePublic,
		UnnamedIdentifier,
		AssemblyNotFound,
		ParamIsntOptional,
		CannotHaveInitVal,
		ParamAlreadySpecified,
		ParamNotSpecified,
		IdDescPtrFromLocal,
		ForInvalidTupleSize,
		ForInvalidOp,
		InvalidAlign,
		NotAlignedEnough,
		IndexOutOfRange,
		MissingPropertyIndices,
		ParamlessSelfIndexer,
		UnimplementedWithIndices,
		OperatorModifiers,
		UnknownOpFunc,
		CastOpInvalidTypes,
		NoncastOpInvalidTypes,
		ArrayInitializerLength,
		ArrayLengthNotSpecified,
		NoMatchingCommand,
		CannotLeaveFinally,
		MustBeType,
		MustBeClass,
		NoIdDataPointer,
		UnassignedReadonly,
		GenericParamCount,
		ParamArrayMustBeTheLast,
		UnnamedParamAfterNamed,
		CatchesAllException,
		NonGenericIdentifier,
        BaseIdNotImplemented,
		
		PreprocWarning = 2000,
		EmptyScope,
		SingleThread,
		AssignSameVar,
		UnreachableCode,
		UnusedId,
		CastToSameType,
		CmpSameVariable,
		AssignedButNeverUsed,
		ConstExpression,
        HidingRequired,
        HidingUnnecessary,

		NoMessage = 3000,
		PreprocInfo,
	}

	public class MessageList
	{
		public MessageStrings Strings;
		public List<string> Messages;
		public object LockObject;
		public bool CollectMessages = true;
#if DEBUG
		public bool ExceptionOnError = false;
#else
		public bool ExceptionOnError = false;
#endif

		public MessageList(MessageStrings Strings = null)
		{
			this.Strings = Strings;
			this.LockObject = new object();
		}

		public void Add(string Message, string Id)
		{
			Add(Id + ": " + Message + ".");
		}

		public void Add(string Message, string Id, string Extra)
		{
			Message = Id + ": " + Message + ": " + Extra + ".";
			Add(Message);
		}

		public void Add(string Message, string Id, string File, int Line, int Char, int Length)
		{
			var PosStr = File + ", " + Line + ", " + Char + ", " + Length;
			Message = Id + "(" + PosStr + "): " + Message + ".";
			Add(Message);
		}

		public void Add(string Message)
		{
			if (!CollectMessages) return;

			lock (LockObject)
			{
				if (Messages == null)
					Messages = new List<string>();

				Messages.Add(Message);
			}
		}

		public void Add(MessageId MessageId, CodeString Extra, params string[] Params)
		{
			if (MessageId == MessageId.NoMessage)
				throw new ArgumentOutOfRangeException("Invalid message", "Message");

			if (Strings == null)
				throw new InvalidOperationException("There's no instance of MessageStrings");

			var Severity = (MessageSeverity)((int)MessageId / 1000 - 1);
			var ErrId = Severity.ToString() + " " + ((int)MessageId).ToString();

			var Description = (string)null;
			if (MessageId != MessageId.PreprocError && MessageId != MessageId.PreprocInfo && MessageId != MessageId.PreprocWarning)
				Description = String.Format(Strings[MessageId.ToString()], Params);

			if (MessageId != Bird.MessageId.EntryNotFound && Severity == MessageSeverity.Error && ExceptionOnError)
				throw new ApplicationException(Description);

			if (Extra.File != null)
			{
				var File = "'" + Path.GetFileName(Extra.File.Path) + "'";
				var Line = Extra.File.GetLineCount(0, Extra.Index) - 1;
				var Char = Extra.Index - Extra.File.GetLinePosition(Line);

				if (Description == null) Description = Extra.ToString();
				Add(Description, ErrId, File, Line, Char, Extra.Length);
			}
			else if (Extra.IsValid)
			{
				Add(Description, ErrId, Extra.ToString());
			}
			else
			{
				Add(Description, ErrId);
			}
		}

		public void Add(MessageId MessageId, String Extra, params string[] Params)
		{
			Add(MessageId, new CodeString(Extra), Params);
		}

		public void Add(MessageId MessageId)
		{
			Add(MessageId, new CodeString());
		}

		public void Add(MessageList List)
		{
			if (!CollectMessages) return;

			lock (LockObject)
			{
				if (Messages == null)
					Messages = new List<string>();

				Messages.AddRange(List.Messages);
			}
		}

		public void WriteToConsole()
		{
			if (Messages != null)
			{
				for (var i = 0; i < Messages.Count; i++)
					Console.WriteLine(Messages[i]);
			}
		}
	}

	public enum ImageFormat : byte
	{
		GUI,
		Console,
		AsDLL,
		DLL,
		MSCoff,
	}

	[Flags]
	public enum CompilerStateFlags : byte
	{
		DebugMode = 1,
		RuntimeChecks = 2,
	}

	public class CompilerState
	{ 
		public DataList Data = new DataList();
		public CompilerStateFlags Flags;
		public BirdBuilder Builder;
		public MessageStrings Strings;
		public MessageList Messages;
		public OperatingSystem OperatingSystem = OperatingSystem.Windows;
		public ImageFormat Format = ImageFormat.GUI;
		public string CodeOutFile, LibOutFile;
		public Stream CodeOut, LibOut;
		public string AssemblyName = "Assembly";

		public GlobalContainer GlobalContainer;
		public IArchitecture Arch;
		public Language Language;

#if DEBUG
		public bool Parallel = false;
#else
		public bool Parallel = true;
#endif
		public string Entry;
		public CallingConvention DefaultCallConv = CallingConvention.BirdCall;
		public int TabSize = 4;

		public bool Compile(CodeFile[] CodeFiles, List<AssemblyPath> Assemblies = null, List<IncBinReference> IncBins = null)
		{
			Reset();
			InitializeScopes(CodeFiles);
			DefineMacroes();

			if (Assemblies != null)
			{
				var RetValue = true;
				for (var i = 0; i < Assemblies.Count; i++)
					if (GlobalContainer.GetLoadedAssembly(Assemblies[i].Name) == null)
					{
						if (GlobalContainer.LoadAssembly(Assemblies[i]) == null)
							RetValue = false;
					}

				if (!RetValue)
					return false;
			}

			if (IncBins != null)
			{
				var RetValue = true;
				for (var i = 0; i < IncBins.Count; i++)
				{
					var File = IncBins[i].File;
					var FileInfo = new FileInfo(File);

					if (!FileInfo.Exists)
					{
						Messages.Add(MessageId.FileDoesntExists, new CodeString(File));
						RetValue = false;
						continue;
					}

					var IncBin = new IncludedBinary(IncBins[i].Name, File, FileInfo.Length);
					GlobalContainer.IncludedBinaries.Add(IncBin);
				}

				if (!RetValue)
					return false;
			}

			GlobalContainer.SearchCommonIdentifiers();
			return Arch.Compile(this, CodeFiles);
		}

		void DefineMacroes()
		{
            var Preprocessor = GlobalContainer.Preprocessor;
            if (OperatingSystem == OperatingSystem.Windows) Preprocessor.Define("OPERATING_SYSTEM", "Windows");
            else if (OperatingSystem == OperatingSystem.Linux) Preprocessor.Define("OPERATING_SYSTEM", "Linux");
            else if (OperatingSystem == OperatingSystem.MacOSX) Preprocessor.Define("OPERATING_SYSTEM", "MacOSX");
			else throw new ApplicationException();
		}

		void InitializeScopes(CodeFile[] CodeFiles)
		{
			if (string.IsNullOrEmpty(AssemblyName))
				throw new InvalidOperationException("Assembly hasn't been set up");

			if (CodeOut == null || LibOut == null)
				throw new InvalidOperationException("Output streams haven't been set up");

			var Random = new Random();
			var Assembly = new Assembly(this, AssemblyName);
			Assembly.Random = Random.Next();

			GlobalContainer = new GlobalContainer(this);
			GlobalContainer.OutputAssembly = Assembly;
			
			for (var i = 0; i < CodeFiles.Length; i++)
			{
				var AssemblyScope = new AssemblyScope(GlobalContainer, Assembly, CodeFiles[i]);
				GlobalContainer.GlobalNamespace.AddScope(AssemblyScope);
				GlobalContainer.Children.Add(AssemblyScope);
			}

			GlobalContainer.GlobalNamespaceScope = new AssemblyScope(GlobalContainer, Assembly);
			GlobalContainer.GlobalNamespace.AddScope(GlobalContainer.GlobalNamespaceScope);
			GlobalContainer.Children.Add(GlobalContainer.GlobalNamespaceScope);
		}

		public CompilerState(BirdBuilder Builder, MessageStrings Strings, IArchitecture Arch, Language Language)
		{
			Messages = new MessageList(Strings);

			this.Builder = Builder;
			this.Arch = Arch;
			this.Language = Language;
			this.Strings = Strings;
		}

		public string GenerateName(Identifier Id)
		{
			if (Id == null)
				throw new ArgumentNullException("Id");

			var Out = (string)null;
			var Gens = Language.NameGenerators;
            for (var i = 0; i < Gens.Length; i++)
			{
				var Res = Gens[i].GenerateName(this, Id, ref Out);
				if (Res != SimpleRecResult.Unknown)
				{
					if (Res == SimpleRecResult.Succeeded)
					{
						if (string.IsNullOrEmpty(Out))
							throw new ApplicationException("Generated identifier name cannot be null or empty");

						return Out;
					}

					if (Res == SimpleRecResult.Failed)
						throw new ApplicationException("Failed to generate identifier name");
				}
			}

			throw new ApplicationException("None of the name generators can handle this identifier");
		}

		public void SetOutput(string CodeOut, string LibOut)
		{
			CodeOutFile = CodeOut = Path.GetFullPath(CodeOut);
			LibOutFile = LibOut = Path.GetFullPath(LibOut);

			this.CodeOut = new FileStream(CodeOut, FileMode.Create);
			this.LibOut = new FileStream(LibOut, FileMode.Create);
		}

		public void SetOutput(Stream CodeOut, Stream LibOut)
		{
			this.CodeOut = CodeOut;
			this.LibOut = LibOut;
		}

		public void DisposeOutput()
		{
			CodeOut.Dispose();
			LibOut.Dispose();
		}

		public int CalcPow2Size(int Size)
		{
			var M = Arch.MaxStructPow2Size;
			if (Size < M) return Helper.Pow2(Size);
			else if (Size % M != 0) return Size + (M - Size % M);
			else return Size;
		}

		public CompilerState(BirdBuilder Builder, IArchitecture Arch, Language Language)
			: this(Builder, new MessageStrings(), Arch, Language)
		{
		}

		public void Reset()
		{
			_AutoLabelIndex = 0;
		}

		int _AutoLabelIndex = 0;
		public int AutoLabel
		{
			get
			{
				if (!Parallel) _AutoLabelIndex++;
				else Interlocked.Increment(ref _AutoLabelIndex);
				return _AutoLabelIndex;
			}
		}

		public CodeString AutoVarName
		{
			get
			{
				return new CodeString(AutoLabel.ToString());
			}
		}

		public CodeString GetInnerScope(CodeString Code)
		{
			if (Language.InnerScopeRecognizer == null) return Code;
			return Language.InnerScopeRecognizer.GetInnerScope(this, Code);
		}

		public CodeString GetInnerScope(CodeString Code, CodeString Command, bool Warning = true)
		{
			var Inner = GetInnerScope(Code);
			if (!Inner.IsValid) return new CodeString();

			Inner = Inner.Trim();
			if (Inner.Length == 0 && Warning)
				Messages.Add(MessageId.EmptyScope, Command);

			return Inner;
		}

		public CodeString GetInnerScope(CodeString Code, int Position, bool Warning = true)
		{
			return GetInnerScope(Code.Substring(Position).Trim(), Code.Substring(0, Position).Trim(), Warning);
		}

		public FunctionParameter[] GetParameters(IdContainer Container, CodeString Parameters)
		{
			var DeclList = VarDeclarationList.Create(Container, Parameters);
			if (DeclList == null) return null;

			var RetValue = DeclList.ToFuncParams(new PluginForGlobals(Container), Mode: VarDeclConvMode.Normal);
			if (RetValue == null || RetValue.Contains(null)) return null;
			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)


Written By
Software Developer
Hungary Hungary
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions