![]() |
|
Making your own programming language - Printable Version +- Sinisterly (https://sinister.li) +-- Forum: Coding (https://sinister.li/Forum-Coding) +--- Forum: Coding (https://sinister.li/Forum-Coding--71) +--- Thread: Making your own programming language (/Thread-Making-your-own-programming-language) |
Making your own programming language - Slarek - 10-29-2013 Making your own programming language Everyone of us has thought about making a programming language but it hasn't gone further than making an interpreter or it has completely stopped because it turned out to be harder than you thought. This tutorial will give you the basic knowledge which helps you to build your own language. The language doesn't fill up all the definitions of a programming language (e.g You can't program the Turing's computer) but it will still give you the example of interpreter's functioning. In our language we have 3 commands(+, -, #) and every of those commands takes 1 byte of space. # prints the value of 8 byte integer, + increases the value by one and - decreases the value by one. These commands will be changed into the format which CPU understands e.g "+" will be two-byte set, "FE C0" in hexa. Number values are not pulled out of the hat but they're machine-readable values for Assembly-command "inc al" which increases the al-register's value by one and is equivalent to command "i++" in C. When programming in Assembly, compiler converts symbolic commands into numeric values but when making a compiler, you have to do this by yourself. Of course you need to know how to program in Assembly so you can make those functions. Possible way is to make only the basics and then make it advanced one by one. x86 assembly language Introduction to x64 Assembly Code: #include <stdio.h>
/* Filenames */
char _output[] = "a.com", _input[] = "a.txt";
/* Interpretation works also */
/* When value is 0, it will be compiled instead of interpreted. */
unsigned char interpret = 0;
/* When interpreting, this is equal to the register's al value */
unsigned char byte;
/*
The script is not implemented as a subroutine
Script prints the wanted character
Character will be printed from al register(8 byte).
Printing will happen by using suspension of DOS, 10h.
In this case, ah in register is a printed code 0Eh.
*/
char print_char[] = {
/* push bx */ 0x53,
/* push ax */ 0x50,
/* mov ah, 0Eh */ 0xB4, 0x0E,
/* xor bx, bx */ 0x33, 0xDB,
/* int 10h */ 0xCD, 0x10,
/* pop ax */ 0x58,
/* pop bx */ 0x5B
};
/*
Command increases the value of al register
*/
char increase[] = {
/* inc al */ 0xFE, 0xC0
};
/*
Command decreases the value of al register
*/
char decrease[] = {
/* dec al */ 0xFE, 0xC8
};
/*
Command initializes the program:
Register al will be set to 0.
*/
char init[] = {
/* xor al, al */ 0x32, 0xC0
};
/*
Script will leave the program by DOS suspension
*/
char quit[] = {
/* mov ah, 4Ch */ 0xB4, 0x4C,
/* int 21h*/ 0xCD, 0x21
};
/*
Takes a character for parameter and writes commands to the file which are equilevant to the parameter
*/
void write_equivalent(unsigned char command)
{
FILE *file = 0;
/* Open the file where the program will be written */
if(!interpret) file = fopen(_output, "ab");
switch(command){
/* Following commands will be read from the file */
case '+':
/* Increase the value of a characterLisätään merkin arvoa */
interpret?++byte:
/* Write the corresponding command to the file */
fwrite(increase, sizeof(increase), 1, file);
break;
case '-':
/* Decrease the value of a character */
interpret?--byte:
/* Write the corresponding command to the file */
fwrite(decrease, sizeof(decrease), 1, file);
break;
case '#':
/* Print characters */
interpret?putchar(byte):
/* Write the corresponding command to the file */
fwrite(print_char, sizeof(print_char), 1, file);
break;
/* Following commands are for interval use */
case '{':
/* Initialize the program */
interpret?byte = 0:
/* Write the corresponding command to the file */
fwrite(init, sizeof(init), 1, file);
break;
case '}':
/* Program will be shut with an end commands */
if(!interpret) fwrite(quit, sizeof(quit), 1, file);
break;
/* Other characters will be bypassed */
default:
break;
}
/* Close the file if it's open */
if(file){ fclose(file);
/* If the file is not open and it hasn't been interpreted, show an error message */
if(!interpret) puts("Error: File could not be opened!");}
}
int main(void)
{
/* To read the character from the file */
int a;
/* Open the sourcefile */
FILE *file;
file = fopen(_input, "r");
/* Check if opening the file was succesful */
if(!file){
puts("File could not besss opened.");
return 1;
}
/* Empy the target file */
FILE *target = fopen(_output, "w");
fclose(target);
/* Write the start of the program to the file */
write_equivalent('{');
/* We use a while-loop to read the file */
while((a = fgetc(file)) != EOF){
write_equivalent(a);
}
/* Write the end of the program to the file */
write_equivalent('}');
/* Close the sourcefile */
fclose(file);
return 0;
}Things that you should note There are few weird things in this code. This is why you should read this code as a pseudo code but this is easier to demonstrate with C since i have "real" commands in use. As far as i know, this works only with certain processors and operating system(check .com as an output) I know it's not very good programming practice to make a program for only certain OS's or processors but the reason is that i developed this ages ago with my old laptop(which OS is Windows XP) and i haven't had enough interest to make it flexible. This code is probably not going to work on any other Windows OS than XP, especially not in Linux:Ambivalent: One reason for this could also be that MS-DOS suspension(int command) doesn't work just like that on other OS's. If you really want to try this code, you can either try DOS-emulator or look for native suspension for your operating system. And why the output is .com? This code didn't print right binaries and XP seem to handle .exe and .com the same way if valid header was not found.(COM-files are downloaded from address 0x100 and it's run like that without making any changes) So the assignment was to either change the output to .com or add a valid DOS-header(which would have complicate the code a lot) So i decided to change the output to .com Thank you for reading!:Smile: Making your own programming language - Slarek - 10-29-2013 Making your own programming language Everyone of us has thought about making a programming language but it hasn't gone further than making an interpreter or it has completely stopped because it turned out to be harder than you thought. This tutorial will give you the basic knowledge which helps you to build your own language. The language doesn't fill up all the definitions of a programming language (e.g You can't program the Turing's computer) but it will still give you the example of interpreter's functioning. In our language we have 3 commands(+, -, #) and every of those commands takes 1 byte of space. # prints the value of 8 byte integer, + increases the value by one and - decreases the value by one. These commands will be changed into the format which CPU understands e.g "+" will be two-byte set, "FE C0" in hexa. Number values are not pulled out of the hat but they're machine-readable values for Assembly-command "inc al" which increases the al-register's value by one and is equivalent to command "i++" in C. When programming in Assembly, compiler converts symbolic commands into numeric values but when making a compiler, you have to do this by yourself. Of course you need to know how to program in Assembly so you can make those functions. Possible way is to make only the basics and then make it advanced one by one. x86 assembly language Introduction to x64 Assembly Code: #include <stdio.h>
/* Filenames */
char _output[] = "a.com", _input[] = "a.txt";
/* Interpretation works also */
/* When value is 0, it will be compiled instead of interpreted. */
unsigned char interpret = 0;
/* When interpreting, this is equal to the register's al value */
unsigned char byte;
/*
The script is not implemented as a subroutine
Script prints the wanted character
Character will be printed from al register(8 byte).
Printing will happen by using suspension of DOS, 10h.
In this case, ah in register is a printed code 0Eh.
*/
char print_char[] = {
/* push bx */ 0x53,
/* push ax */ 0x50,
/* mov ah, 0Eh */ 0xB4, 0x0E,
/* xor bx, bx */ 0x33, 0xDB,
/* int 10h */ 0xCD, 0x10,
/* pop ax */ 0x58,
/* pop bx */ 0x5B
};
/*
Command increases the value of al register
*/
char increase[] = {
/* inc al */ 0xFE, 0xC0
};
/*
Command decreases the value of al register
*/
char decrease[] = {
/* dec al */ 0xFE, 0xC8
};
/*
Command initializes the program:
Register al will be set to 0.
*/
char init[] = {
/* xor al, al */ 0x32, 0xC0
};
/*
Script will leave the program by DOS suspension
*/
char quit[] = {
/* mov ah, 4Ch */ 0xB4, 0x4C,
/* int 21h*/ 0xCD, 0x21
};
/*
Takes a character for parameter and writes commands to the file which are equilevant to the parameter
*/
void write_equivalent(unsigned char command)
{
FILE *file = 0;
/* Open the file where the program will be written */
if(!interpret) file = fopen(_output, "ab");
switch(command){
/* Following commands will be read from the file */
case '+':
/* Increase the value of a characterLisätään merkin arvoa */
interpret?++byte:
/* Write the corresponding command to the file */
fwrite(increase, sizeof(increase), 1, file);
break;
case '-':
/* Decrease the value of a character */
interpret?--byte:
/* Write the corresponding command to the file */
fwrite(decrease, sizeof(decrease), 1, file);
break;
case '#':
/* Print characters */
interpret?putchar(byte):
/* Write the corresponding command to the file */
fwrite(print_char, sizeof(print_char), 1, file);
break;
/* Following commands are for interval use */
case '{':
/* Initialize the program */
interpret?byte = 0:
/* Write the corresponding command to the file */
fwrite(init, sizeof(init), 1, file);
break;
case '}':
/* Program will be shut with an end commands */
if(!interpret) fwrite(quit, sizeof(quit), 1, file);
break;
/* Other characters will be bypassed */
default:
break;
}
/* Close the file if it's open */
if(file){ fclose(file);
/* If the file is not open and it hasn't been interpreted, show an error message */
if(!interpret) puts("Error: File could not be opened!");}
}
int main(void)
{
/* To read the character from the file */
int a;
/* Open the sourcefile */
FILE *file;
file = fopen(_input, "r");
/* Check if opening the file was succesful */
if(!file){
puts("File could not besss opened.");
return 1;
}
/* Empy the target file */
FILE *target = fopen(_output, "w");
fclose(target);
/* Write the start of the program to the file */
write_equivalent('{');
/* We use a while-loop to read the file */
while((a = fgetc(file)) != EOF){
write_equivalent(a);
}
/* Write the end of the program to the file */
write_equivalent('}');
/* Close the sourcefile */
fclose(file);
return 0;
}Things that you should note There are few weird things in this code. This is why you should read this code as a pseudo code but this is easier to demonstrate with C since i have "real" commands in use. As far as i know, this works only with certain processors and operating system(check .com as an output) I know it's not very good programming practice to make a program for only certain OS's or processors but the reason is that i developed this ages ago with my old laptop(which OS is Windows XP) and i haven't had enough interest to make it flexible. This code is probably not going to work on any other Windows OS than XP, especially not in Linux:Ambivalent: One reason for this could also be that MS-DOS suspension(int command) doesn't work just like that on other OS's. If you really want to try this code, you can either try DOS-emulator or look for native suspension for your operating system. And why the output is .com? This code didn't print right binaries and XP seem to handle .exe and .com the same way if valid header was not found.(COM-files are downloaded from address 0x100 and it's run like that without making any changes) So the assignment was to either change the output to .com or add a valid DOS-header(which would have complicate the code a lot) So i decided to change the output to .com Thank you for reading!:Smile: RE: Making your own programming language - Ex094 - 10-30-2013 I think you meant Interpreter instead of a Compiler, same as noize said RE: Making your own programming language - Ex094 - 10-30-2013 I think you meant Interpreter instead of a Compiler, same as noize said RE: Making your own programming language - Slarek - 10-30-2013 I'll change it. Thanks for reply RE: Making your own programming language - Slarek - 10-30-2013 I'll change it. Thanks for reply RE: Making your own programming language - noize - 11-01-2013 I think you should bring the changes you made somewhere else here as well. Keep going. RE: Making your own programming language - noize - 11-01-2013 I think you should bring the changes you made somewhere else here as well. Keep going. RE: Making your own programming language - Slarek - 11-01-2013 (11-01-2013, 12:25 PM)noize Wrote: I think you should bring the changes you made somewhere else here as well. Indeed. Thanks for remembering, i can't do anything with this fish memory:/ RE: Making your own programming language - Slarek - 11-01-2013 (11-01-2013, 12:25 PM)noize Wrote: I think you should bring the changes you made somewhere else here as well. Indeed. Thanks for remembering, i can't do anything with this fish memory:/ |