Anyone here made their own programming language?

Off-topic talk on music, art, literature, games and forum games.
Post Reply
teo123
Master in Training
Posts: 520
Joined: Tue Oct 27, 2015 3:46 pm
Religion: None (Atheist)
Diet: Vegan

Anyone here made their own programming language?

Post by teo123 » Sun Dec 30, 2018 5:06 am

So, has anyone here made their own programming language?
I have. I call it AEC (Arithmetic Expression Compiler). I've designed it to be extremely low-level and integrate as seamlessly as possible with Assembly. The compiler makes no assumptions about the operating system, it simply outputs i486-compatible assembly for arithmetic expressions and expects you to do everything else in assembly (including variable declarations and setting up the system stack).
Here are my first two programs written in it:

Code: Select all

;So, this was my first program written in my own programming language. I call it AEC.
;Warning: The comments about arrays don't apply to this version of AEC any more. See "fibonacci.aec" for more information!
AsmStart ;This part of code is Windows-dependent, so it has to be done in inline assembly.
	debug=0
	format PE console
	entry start

	include 'win32a.inc'

	section '.text' code executable
	start:
AsmEnd
i:=1
j:=1
While i<101
	j:=1
	While j<101
        AsmStart
            if debug=1 ;Invoking FlatAssembler preprocessor.
				fld dword [j]
				fstp qword [esp+12]
				fld dword [i]
				fstp qword [esp+4]
				mov dword [esp],_debugOutput1
				call [printf]
			end if
        AsmEnd
		If i>j
			a:=i
			b:=j
		Else
			a:=j
			b:=i
		EndIf
        While (b>1/100)&(a>1/100) ;Modified version of the Euclid's algorithm.
			If a>b
				a:=mod(a,b)
			Else
				b:=mod(b,a)
			EndIf
        EndWhile ;There is a reason why BASIC used different keywords for "EndIf" and "EndWhile", because they are trivial to translate to Assembly :-).
		subscript:=i*101+j
		If a>1/100
            gcd[subscript]:=a ;Warning: Arrays are write-only in this version of AEC, they have to be read in inline Assembly. Hopefully that's not too hard.
		Else
			gcd[subscript]:=b
		EndIf
        AsmStart
			if debug=1
				fld dword [a]
				fstp qword [esp+20]
				fld dword [j]
				fstp qword [esp+12]
				fld dword [i]
				fstp qword [esp+4]
				mov dword [esp],_debugOutput2
				call [printf]
				mov dword [esp],_pause
				call [system]
			end if
        AsmEnd
		j:=j+1
	EndWhile
	i:=i+1
EndWhile
AsmStart
mov dword [esp],_output1
call [printf]
mov dword [esp+4],firstNumber
mov dword [esp],_input1
call [scanf]

mov dword [esp],_output2
call [printf]
mov dword [esp+4],secondNumber
mov dword [esp],_input1
call [scanf]

fild dword [firstNumber]
fstp dword [a]
fild dword [secondNumber]
fstp dword [b]
AsmEnd
subscript:=4*(a*101+b) ;While you need to use inline Assembly to read arrays, you can still calculate subscripts in AEC.
AsmStart
fld dword [subscript]
fistp dword [subscript]
mov ebx,[subscript]
fld dword [gcd+ebx]
fst qword [esp+4]
mov dword [esp],_output3
call [printf]
invoke system,_pause
invoke exit,0

_debugOutput1 db "DEBUG: Attempting to calculate the GCD of %f and %f.",10,0
_debugOutput2 db "DEBUG: GCD of %f and %f is %f.",10,0
_output1 db "Enter the first number (whole number 1-100): ",0
_input1 db "%d",0
_output2 db "Enter the second number (whole number 1-100): ",0
_pause db "PAUSE",0
_output3 db "Their greatest common divisor is: %f",10,0

section '.rdata' readable writable ;Yes, you are expected to declare the variables yourself in inline assembly, as the way it's done varies greatly from one operating system to another.
result dd ?
a dd ?
b dd ?
i dd ?
j dd ?
firstNumber dd ?
secondNumber dd ?
subscript dd ?
gcd dd 101*101 dup(?)

section '.idata' data readable import ;Those functions can't be called from this version of AEC (as the way to call them in Assembly varies from one operating system to another), they have to be called from inline Assembly.
library msvcrt,'msvcrt.dll'
import msvcrt,printf,'printf',system,'system',exit,'exit',scanf,'scanf'
AsmEnd

Code: Select all

;So, this is my second program in my own programming language.
AsmStart
	debug=0
	format PE console
	entry start

	include 'win32a.inc'

	section '.text' code executable
	start:

	mov dword [esp],_output1
	call [printf]
	mov dword [esp+4],n
	mov dword [esp],_input1
	call [scanf]
AsmEnd
fib(0):=0
fib(1):=1
i:=2
While i<n+1
	fib(i):=fib(i-1)+fib(i-2) ;Good idea, QBASIC! Treating Assembly arrays as functions, I would have never thought of that! It's really easy to program.
	i:=i+1
EndWhile
subscript:=(i-1)*4
AsmStart
	fld dword [subscript]
	fistp dword [subscript]
	mov ebx,[subscript]
	fld dword [fib+ebx]
	fstp qword [esp+4]
	mov dword [esp],_output2
	call [printf]
	mov dword [esp],_pause
	call [system]
	mov dword [esp],0
	call [exit]

_output1 db "Enter n (0-100): ",0
_output2 db "The n-th Fibonacci number is: %f",10,0
_input1 db "%f",0
_pause db "PAUSE",0

section '.rdata' readable writable
result dd ? ;Yes, you need to declare it to be used internally by AEC. Hope you don't mind! :-)
n dd ?
i dd ?
subscript dd ?
fib dd 100 dup(?)

section '.idata' data readable import
library msvcrt,'msvcrt.dll'
import msvcrt,printf,'printf',system,'system',exit,'exit',scanf,'scanf'
AsmEnd
Even after almost 11 months of work, it's little more than just a toy, and I don't have the time to continue developing it. I believe it's Turing-complete now, but I don't know how to actually prove it. However, I feel I've gained a lot of useful programming experience with it. And, who knows, maybe somebody will fork it and modify it into something more useful! I'm also dreaming about making a LISP-like language in which you will be able to use both S-expressions and infix-expressions for arithmetic expressions, but only S-expressions elsewhere (since they come very handy in string and array manipulation).
You can try it here (yes, the native version is a little hard to install right now, and the on-line version doesn't have all the features because of the limitations imposed by browsers for security reasons):
http://flatassembler.000webhostapp.com/compiler.html
To make all the features it has now, I used seven programming languages, some of which I've first used there (C, Assembly, JavaScript, HTML, CSS, PHP and some SVG).
Do you have some similar experience?

User avatar
cornivore
Full Member
Posts: 204
Joined: Wed Jun 20, 2018 3:23 am
Religion: Other
Diet: Vegan

Post by cornivore » Mon Dec 31, 2018 9:55 am

Not me, but here's an idea for another program that you might have fun with: This Website holds a collection of the Song 99 Bottles of Beer programmed in different programming languages . . . Here's my version in HTML: http://www.99-bottles-of-beer.net/lyrics.html ;)

teo123
Master in Training
Posts: 520
Joined: Tue Oct 27, 2015 3:46 pm
Religion: None (Atheist)
Diet: Vegan

Post by teo123 » Mon Dec 31, 2018 2:22 pm

Done that... barely. Damn, the compiler I've made sometimes outputs error messages that are useless even to me!

Code: Select all

AsmStart
	macro pushIntToStack x
	{
		sub esp,4
		fld dword [x]
		fistp dword [esp]
	}
	macro pushStringToStack x
	{
		sub esp,4
		mov dword [esp],x
	}
	format PE console
	entry start

	include 'win32a.inc'

	section '.text' code executable
	start:
AsmEnd
	i:=99
	While i>(-1)
		iSub1:=i-1
		If i>1
			AsmStart
				pushIntToStack iSub1
				pushIntToStack i
				pushIntToStack i
				jmp label1
				output1:
					db "%d bottles of beer on the wall, %d bottles of beer.",10
					db "Take one down and pass it around, %d bottles of beer on the wall.",10,10,0
				label1:
				pushStringToStack output1
				call [printf]
			AsmEnd
		Else
			If i=0
				AsmStart
					jmp label2
					output2:
						db "No more bottles of beer on the wall, no more bottles of beer.",10
						db "Go to the store and buy some more, 99 bottles of beer on the wall.",10,0
					label2:
					pushStringToStack output2
					call [printf]
				AsmEnd
			Else
				AsmStart
					pushIntToStack i
					pushIntToStack i
					jmp label3
					output3:
						db "%d bottle of beer on the wall, %d bottle of beer.",10
						db "Take one down and pass it around, no more bottles of beer on the wall.",10,10,0
					label3:
					pushStringToStack output3
					call [printf]
				AsmEnd
			EndIf
		EndIf
		i:=i-1
	EndWhile
AsmStart
invoke system,_pause
invoke exit,0

_pause db "PAUSE",0

section '.rdata' readable writable
result dd ?
i dd ?
iSub1 dd ?

section '.idata' data readable import
library msvcrt,'msvcrt.dll'
import msvcrt,printf,'printf',system,'system',exit,'exit',scanf,'scanf'

AsmEnd

User avatar
cornivore
Full Member
Posts: 204
Joined: Wed Jun 20, 2018 3:23 am
Religion: Other
Diet: Vegan

Post by cornivore » Mon Dec 31, 2018 3:10 pm

Beers (I mean Cheers)!

teo123
Master in Training
Posts: 520
Joined: Tue Oct 27, 2015 3:46 pm
Religion: None (Atheist)
Diet: Vegan

Post by teo123 » Sun Jan 06, 2019 6:15 am

Here is another program I've made using it:

Code: Select all

;Advanced example: implementing the permutation algorithm.
AsmStart
    debug=0
	macro pushIntToStack x
	{
		sub esp,4
		fld dword [x]
		fistp dword [esp]
	}
	macro pushPointerToStack x
	{
		sub esp,4
		lea ebx,[x]
		mov [esp],ebx
	}
	macro pushStringToStack x
	{
		sub esp,4
		mov dword [esp],x
	}
	format PE console
	entry start

	include 'win32a.inc'

	section '.text' code executable
	start:
	jmp enterNumber$
		enterNumber db "Enter a whole number (1 - 1'000'000).",10,0
	enterNumber$:
	pushStringToStack enterNumber
	call [printf]
	pushPointerToStack original
	jmp floatSign$
		floatSign db "%f",0
	floatSign$:
	pushStringToStack floatSign
	call [scanf]
	jmp permutationString$
		permutationString db "The permutations of its digits are:",10,0
	permutationString$:
	pushStringToStack permutationString
	call [printf]
AsmEnd
numberOfDigits:=0
i:=0
While i<10
	countDigits[i]:=0
	i:=i+1
EndWhile
While original>0
	numberOfDigits:= numberOfDigits + 1
	lastDigit:= mod( original , 10 )
	countDigits[ lastDigit ]:=countDigits( lastDigit ) + 1
	original:= (original - lastDigit) / 10
EndWhile
AsmStart
	if debug=1
AsmEnd
		i:=0
		While i<10
			subscript:=4*i
			AsmStart
				fld dword [subscript]
				fistp dword [subscript]
				mov ebx,[subscript]
				pushIntToStack (countDigits+ebx)
				pushStringToStack integerSign
				call [printf]
			AsmEnd
			i:=i+1
		EndWhile
		AsmStart
			pushStringToStack newLineString
			call [printf]
		AsmEnd
AsmStart
end if
AsmEnd
topOfMyStack:=1
myStack[(numberOfDigits+1)]:=0
While topOfMyStack>0
	currentNumberOfDigits:=myStack ( topOfMyStack * ( numberOfDigits + 1 ) )
	i:=0
	While i<currentNumberOfDigits
		currentNumber(i):=myStack ( topOfMyStack * ( numberOfDigits + 1 ) + ( i + 1 ) )
		i:=i+1
	EndWhile
	AsmStart
		if debug=1
	AsmEnd
			i:=0
			While i<currentNumberOfDigits
				subscript:=i*4
				AsmStart
					fld dword [subscript]
					fistp dword [subscript]
					mov ebx,[subscript]
					pushIntToStack (currentNumber+ebx)
					pushStringToStack integerSign
					call [printf]
				AsmEnd
				i:=i+1
			EndWhile
			AsmStart
				pushStringToStack newLineString
				call [printf]
			AsmEnd
	AsmStart
		end if
	AsmEnd
	topOfMyStack:=topOfMyStack-1
	If currentNumberOfDigits=numberOfDigits
		i:=0
		While i<numberOfDigits
			subscript:=i*4
			AsmStart
				fld dword [subscript]
				fistp dword [subscript]
				mov ebx,[subscript]
				pushIntToStack (currentNumber+ebx)
				pushStringToStack integerSign
				call [printf]
			AsmEnd
			i:=i+1
		EndWhile
		AsmStart
			pushStringToStack newLineString
			call [printf]
		AsmEnd
	Else
		i:=0
		While i<10
			counter:=0
			j:=0
			While j<currentNumberOfDigits
				If currentNumber(j)=i
					counter:=counter+1
				EndIf
				j:=j+1
			EndWhile
			If counter<countDigits(i)
				topOfMyStack:=topOfMyStack+1
				myStack(topOfMyStack*(numberOfDigits+1)):=currentNumberOfDigits+1
				j:=0
				While j<currentNumberOfDigits
					myStack(topOfMyStack*(numberOfDigits+1)+(j+1)):=currentNumber(j)
					j:=j+1
				EndWhile
				myStack (topOfMyStack * (numberOfDigits + 1) + (j + 1) ) := i
			EndIf
			i:=i+1
		EndWhile
	EndIf
EndWhile
AsmStart
invoke system,_pause
invoke exit,0

_pause db "PAUSE",0
integerSign db "%d",0
newLineString db 10,0

section '.rdata' readable writable
original dd ?
result dd ?
lastDigit dd ?
numberOfDigits dd ?
countDigits dd 11 dup(?)
subscript dd ?
myStack dd 1000 dup(?)
topOfMyStack dd ?
counter dd ?
i dd ?
currentNumber dd 11 dup(?)
currentNumberOfDigits dd ?
j dd ?


section '.idata' data readable import
library msvcrt,'msvcrt.dll'
import msvcrt,printf,'printf',system,'system',exit,'exit',scanf,'scanf'
AsmEnd
This is an excellent example of the power of structural programming. The programming language is really simple (the compiler is less than 2000 lines of code, mostly in JavaScript), but the equivalent program (implementing the stack-based permutation algorithm) in Assembly would be about three times longer than the program I just posted.

teo123
Master in Training
Posts: 520
Joined: Tue Oct 27, 2015 3:46 pm
Religion: None (Atheist)
Diet: Vegan

Post by teo123 » Mon Jan 28, 2019 1:45 am

So, guys, what's your favorite programming language? Mine is without a doubt JavaScript. Many people say it's one of the worst programming languages used in production, but, in my experience, it's the only language that gets things done. Almost like magic.
I mean, I spent five years trying to learn how to program. And I couldn't dream of making a PacMan game in any of the languages I tried to learn. Then, after just three weeks of studying JavaScript, I was able to make a Pac-Man game playable on smartphones, see here. And, after six months of learning JavaScript, I was able to make a web-app that converts arithmetic expressions to i486-compatible assembly. And I wasn't far away from making a compiler for my own simple programming language, something I've dreamed about since the very beginning.

Post Reply

Who is online

Users browsing this forum: No registered users and 53 guests