Programming and general geekiness.

Posts tagged ‘how to make a programming language’

ThomasScript source code

Because ThomasScript isn’t finished yet and I really am not worried about licensing it because it takes too much time (for my liking) I have decided to just put it here, on my blog. Because it doesn’t have a license I have decided to invent the following:

  1. If there are compiling errors, tell me
  2. If there are running errors, tell me
  3. If you computer (or anything else) is damaged because of the source code don’t tell me – it can be your fault for downloading it
That’s quite a simple version of GPL! Here is the code anyway:
import java.io.*;
import javax.swing.*;
import java.util.*;

class ThomasScript
{
	public String[] variables = new String[10000];
	public String[] values = new String[10000];
	public int next = 0;
	public Scanner in = new Scanner(System.in);
	
	public static void main(String[] args)
	{
		System.out.println("Welcome to ThomasScript");
		System.out.println("Recognized request from: " + args[0]);
		File source = new File(args[0]);
		if (source.exists())
		{
			System.out.println("Can confirm that the source exists");
			try
			{
				FileReader fr = new FileReader(args[0]);
				String code = "";
				BufferedReader buffer = new BufferedReader(fr);
				String line = "";
				String[] lines = new String[100000]; //CHANGE NUMBER TO NUMBER OF LINES IN FILE!!
				int nextone = 0;
				while ((line = buffer.readLine()) != null)
				{
					lines[nextone] = line;
					nextone++;
				}
				ThomasScript ts = new ThomasScript();
				ts.runCode(lines);
			}
			catch (IOException e)
			{
				System.out.println("Sorry, some sort of error occured.");
			}
		}
		else System.out.println("Sorry, file doesn't exist");
	}
	
	void runCode(String[] lines)
	{
		ThomasScript ts = new ThomasScript();
		System.out.println("Running code");
		System.out.println("-------------------------------------");
		System.out.println("");
		int max = 0;
		//Identifies the max number, temporary code only
		for (int a = 0; a < lines.length; a++)
		{
			if (lines[a] == null)
			{
				max = a;
				break;
			}
		}
		int a = 0;
		while (true)
		{
			if (lines[a] == null) break;
			String[] components = lines[a].trim().split(" ");
			String parts = "";
			for (int b = 1; b < components.length; b++) parts += components[b] + " ";
			if (components[0].equals("write"))
			{
				String[] args = getActualStringValues(parts);
				for (int b = 0; b < args.length; b++)
				{	
					if (args[b] == null) break;
					System.out.print(args[b]);
				}
				System.out.print("\n");
			}
			else if (components[0].equals("msg"))
			{
				String[] args = getActualStringValues(parts);
				String fullmessage = "";
				for (int b = 0; b < args.length; b++)
				{	
					if (args[b] == null) break;
					fullmessage += args[b];
				}
				JOptionPane.showMessageDialog(null, fullmessage);
				System.out.print("\n");
			}
			else if (components[0].equals("dim"))
			{
				for (int b = 1; b < components.length; b++)
				{
					variables[next] = components[b];
					values[next] = "";
					next++;
				}
			}
			else if (components[0].equals("set"))
			{
				String toGive = "";
				for (int b = 3; b < components.length; b++) toGive += components[b] + " ";
				toGive = toGive.trim();
				try
				{
					int index = 0;
					for (int b = 0; b < variables.length; b++)
					{
						if (variables[b] != null)
						{
							if (variables[b].equals(components[1]))
							{
								index = b;
								break;
							}
						}
					}
					if (components[2].equals("="))
					{
						String[] valueOut = getActualStringValues(toGive);
						if (valueOut[0] == null) valueOut[0] = toGive;
						values[index] = valueOut[0];
					}
					else if (components[2].equals("+"))
					{
						if (toGive.charAt(0) == '"')
						{
							String[] valueOut = getActualStringValues(toGive);
							values[index] += valueOut[0];
						}
						else if (toGive.charAt(0) == '$')
						{
							if (couldBeInt(getVariableValue(toGive)) && couldBeInt(getVariableValue(components[1])))
							{
								int result = (Integer.parseInt(getVariableValue(components[1])) + Integer.parseInt(getVariableValue(toGive)));
								values[index] = "" + result;
							}
							else
							{
								values[index] += getVariableValue(toGive);
							}
						}
						else if (couldBeInt(toGive))
						{
							int result = (Integer.parseInt(getVariableValue(components[1])) + Integer.parseInt(toGive));
							values[index] = "" + result;
						}
					}
					else if (components[2].equals("-"))
					{
						if (toGive.charAt(0) == '"')
						{
							String[] valueOut = getActualStringValues(toGive);
							values[index] += valueOut[0];
						}
						else if (toGive.charAt(0) == '$')
						{
							if (couldBeInt(getVariableValue(toGive)) && couldBeInt(getVariableValue(components[1])))
							{
								int result = (Integer.parseInt(getVariableValue(components[1])) - Integer.parseInt(getVariableValue(toGive)));
								values[index] = "" + result;
							}
							else
							{
								values[index] += getVariableValue(toGive);
							}
						}
						else if (couldBeInt(toGive))
						{
							int result = (Integer.parseInt(getVariableValue(components[1])) - Integer.parseInt(toGive));
							values[index] = "" + result;
						}
					}
					else if (components[2].equals("*"))
					{
						if (toGive.charAt(0) == '"')
						{
							String[] valueOut = getActualStringValues(toGive);
							values[index] += valueOut[0];
						}
						else if (toGive.charAt(0) == '$')
						{
							if (couldBeInt(getVariableValue(toGive)) && couldBeInt(getVariableValue(components[1])))
							{
								int result = (Integer.parseInt(getVariableValue(components[1])) * Integer.parseInt(getVariableValue(toGive)));
								values[index] = "" + result;
							}
							else
							{
								values[index] += getVariableValue(toGive);
							}
						}
						else if (couldBeInt(toGive))
						{
							int result = (Integer.parseInt(getVariableValue(components[1])) * Integer.parseInt(toGive));
							values[index] = "" + result;
						}
					}
					else if (components[2].equals("/"))
					{
						if (toGive.charAt(0) == '"')
						{
							String[] valueOut = getActualStringValues(toGive);
							values[index] += valueOut[0];
						}
						else if (toGive.charAt(0) == '$')
						{
							if (couldBeInt(getVariableValue(toGive)) && couldBeInt(getVariableValue(components[1])))
							{
								int result = (Integer.parseInt(getVariableValue(components[1])) / Integer.parseInt(getVariableValue(toGive)));
								values[index] = "" + result;
							}
							else
							{
								values[index] += getVariableValue(toGive);
							}
						}
						else if (couldBeInt(toGive))
						{
							int result = (Integer.parseInt(getVariableValue(components[1])) / Integer.parseInt(toGive));
							values[index] = "" + result;
						}
					}					
				}
				catch (Exception e)
				{
					System.out.println(e.toString());
				}
			}
			else if (components[0].equals("get"))
			{
				int index = -1;
				for (int i = 0; i < variables.length; i++)
				{
					if (variables[i].equals(components[1]))
					{
						index = i;
						break;
					}
				}
				if (index == -1) System.out.println("Variable not declared");
				else
				{
					String prompt = "";
					for (int i = 2; i < components.length; i++) prompt += components[i] + " ";
					String[] prompts = getActualStringValues(prompt);
					prompt = "";
					for (int i = 0; i < prompts.length; i++)
					{
						if (prompts[i] == null) break;
						prompt += prompts[i];
					}
					System.out.println(prompt);
					String input = in.nextLine();
					values[index] = input;
				}
			}
			else if (components[0].equals("getnum"))
			{
				int index = -1;
				for (int i = 0; i < variables.length; i++)
				{
					if (variables[i].equals(components[1]))
					{
						index = i;
						break;
					}
				}
				if (index == -1) System.out.println("Variable not declared");
				else
				{
					String prompt = "";
					for (int i = 2; i < components.length; i++) prompt += components[i] + " ";
					String[] prompts = getActualStringValues(prompt);
					prompt = "";
					for (int i = 0; i < prompts.length; i++)
					{
						if (prompts[i] == null) break;
						prompt += prompts[i];
					}
					System.out.println(prompt);
					int input = 0;
					input = in.nextInt();
					values[index] = "" + input;
				}
			}
			else if (components[0].equals("goto"))
			{
				if (couldBeInt(components[1]))
				{
					a = Integer.parseInt(components[1]) - 2;
				}
			}
			else if (components[0].equals("exit") || components[0].equals("quit")) break;
			else if (components[0].equals("if"))
			{
				String $var1 = getActualStringValues(components[1])[0];
				String $var2 = getActualStringValues(components[3])[0];
				int var1 = 0, var2 = 0;
				boolean var1true = false, var2true = false;
				if (couldBeInt($var1))
				{
					var1 = Integer.parseInt($var1);
					var1true = true;
				}
				if (couldBeInt($var2))
				{
					var2 = Integer.parseInt($var2);
					var2true = true;
				}
				
				if (components[2].equals("="))
				{
					if ($var1.equals($var2) && couldBeInt(components[4])) a = Integer.parseInt(components[4]) - 2;
				}
				else if (var1true && var2true)
				{
					if (components[2].equals(">"))
					{
						if (var1 > var2 && couldBeInt(components[4])) a = Integer.parseInt(components[4]) - 2;
					}
					else if (components[2].equals("<"))
					{
						if (var1 < var2 && couldBeInt(components[4])) a = Integer.parseInt(components[4]) - 2;
					}
					else if (components[2].equals(">="))
					{
						if (var1 >= var2 && couldBeInt(components[4])) a = Integer.parseInt(components[4]) - 2;
					}
					else if (components[2].equals("<="))
					{
						if (var1 <= var2 && couldBeInt(components[4])) a = Integer.parseInt(components[4]) - 2;
					}
					else if (components[2].equals("!="))
					{
						if (var1 != var2 && couldBeInt(components[4])) a = Integer.parseInt(components[4]) - 2;
					}
				}
				
			}
			else System.out.println("Unrecognized command on line " + (a+1));
			a++;
		}
		System.out.println("\n-------------------------------------\nRun complete");
	}
	
	String[] getActualStringValues(String parts)
	{
		parts = parts.trim();
		String[] returnOfTheString = new String[parts.length()];
		boolean inString = false;
		boolean inVariable = false;
		int position = -1;
		boolean started = false;
		for (int a = 0; a < parts.length(); a++)
		{
			char c = parts.charAt(a);
			if (c == '"' && !inString)
			{
				position++;
				inString = true;
			}
			else if (c == '"' && inString)
			{
				inString = false;
			}
			else if (inString)
			{
				if (returnOfTheString[position] == null) returnOfTheString[position] = "";
				returnOfTheString[position] += c;
			}
			else if (c == '$' && !inVariable)
			{
				position++;
				inVariable = true;
				returnOfTheString[position] = "$";
			}
			else if ((c == ' ' || a == parts.length()) && inVariable)
			{
				returnOfTheString[position] = getVariableValue(returnOfTheString[position]);
				inVariable = false;
			}
			else if (inVariable)
			{
				returnOfTheString[position] += c;
			}
			else
			{
				
			}
		}
		if (inVariable)
		{
			returnOfTheString[position] = getVariableValue(returnOfTheString[position]);
		}
		return returnOfTheString;
	}
	
	public String getVariableValue(String name)
	{
		int index = 0;
		for (int a = 0; a < variables.length; a++)
		{
			if (variables[a] != null)
			{
				if (variables[a].equals(name))
				{
					index = a;
					break;
				}
			}
		}
		return values[index];
	}
	
	boolean couldBeInt(String value)
	{
		value = value.trim();
		for (int a = 0; a < value.length(); a++)
		{
			char c = value.charAt(a);
			if (c != '0' && c != '1' && c != '2' && c != '3' && c != '4' && c != '5' && c != '6' && c != '7' && c != '8' && c != '9' && c != '.' && c != '-')
			{
				return false;
			}
		}
		return true;
	}
}

ThomasScript update

ThomasScript has know had all it’s basic commands finished except from branching…

ThomasScript will happen

Yesterday I finally got round to deciding that I would code ThomasScript. I had written some code about a month ago that roughly worked out how I could get started – but that was in C#, so today I have been porting it all over to Java. So far I have a relatively simple 150 line Java file that allows for ‘string evaluation’ and the write command. Here are the total commands:

Branching Commands:

  • if
  • else if
  • else
  • for
  • while

General commands:

  • write*
  • get
  • getnum
  • dim*
  • random
  • set

Variables:

  • PI – 3.141592
  • NEWLINE – \n
  • THEANSWERTOTHELIFEUNIVERSEANDEVERYTHING – 42
*Infinite arguments
I’ll probably add some more, but this is the basics of the language for now – it will be improved.

How to build a really simple programming language

This is not a tutorial. It is more a guide of how you could first approach things. It is assumed that you code in some object-orientated language. I think Java would be the best thing to get started with for this. I have based this on some code that I have already written as part of my ThomasScript project, which I intend to release at some point. Maybe.

First of all, I must assume that your programming language (and mine) and simple non-OO languages that have their code written out in text files, or somehow read text into some sort of String object to use as the basis of their ‘code’. Like you have a BASIC interpreter (which you would write) and a .BAS file that someone else would write and run. I’ll let you worry about how you get the content of the .BAS file.

Now that you have roughly figured this out, you need to think about how you are going to structure your language. Here is a rough example of mine:

dim $variable

set $variable = “Hello”

write $avariable

getnum $variable

set $variable + 1

write $variable

if ($variable > 10)

write “Big number”

else

write “Small number”

write “Going to run a function”

run someCode “Hello!”

code someCode $text

write $text

I think it is relatively clear how this program works and indeed how the programming language works – even though it is very simple. The first part of coding the language is to split everything into array, split into individual lines. You then take apart the first line by its spaces: dim and $variable. There is therefore a switch branch in your code that has all of these possible language keywords. The code for dim is found and the argument $variable is given to it. For simplicity purposes all variables start with a dollar symbol for easy lookup. The variable names are stored in a string array with a length of about 10,000 because it is unlikely that you’ll need more, or that you are using a language that allows for arrays of unlimited length. There is then another array with type of object (or equivalent) that stores the variable values. This is relatively simple.

Because it is relatively clear how all the other functions work from this, the next thing to look at is basic (very basic) logic. I have decided that to keep things simple at first I will only use >, <, ==, !=, <= and >=. I will not use any variation on AND or OR. The value in the brackets is now relatively easy to evaluate; you simply get the left hand value and compare using the appropriate operation to the right. After this you get all the code that is indented and run that.

This is a very basic article and doesn’t really discuss the full process, however it certainly offers a simple start. Please note I plan to write a simple version of ThomasScript to the syntax described above before releasing the source code (either C, C++ or Java).

Follow

Get every new post delivered to your Inbox.