Впервые я познакомился с программированием в 6 классе… Тогда это был старинный компилятор borland pascal, который мог запускаться только с помощью эмулирования MS-DOS. С тех пор прошло 6 лет… Маленький мальчик вырос и стал писать более читаемый код, а судьба привела его в один из лучших технических вузов страны. Но те 6 лет не прошли даром. В течение них накапливался огромный пласт противоречий, которые заставляли его искать все более и более совершенный язык… Так появился на свет Ctag — продукт переосмысления достижений человечества.
Скажу сразу, что опыта работы над большими серьезными проектами у меня пока нет, да и знаний может быть не так много, так что буду рад любым ценным комментариям с вашей стороны. Также язык находится пока в стадии совсем ранней альфы (полностью без компилятора), и поэтому он может не раз поменяться и, если найдутся энтузиасты, то буду благодарен всякой сторонней помощи.
Давайте подумаем, что обязательно нужно современному языку программирования. Для ответа на этот вопрос не нужно далеко ходить. Достаточно посмотреть на самые популярные и быстро набирающие популярность языки программирования. Я бы выделил следующую четверку (на основании этой и этой статей):
- С/C++
- Java и C#
- Python
- JavaScript
Теперь разберем подробнее каждый из языков.
Языки С/C++ были разработаны еще в доисторические времена (1970-80 года), но и сегодня их продолжают использовать для реализации высоко производительных систем, потому что их код легко компилируется в код ассемблера без существенной потери производительности. Java и С# являются очень устойчивыми языками по отношению к окружающим их средам. Python радует своей простотой и удобностью при написании кода (хотя, честно сказать, это мой самый нелюбимый язык программирования). Ну и наконец, JavaScript очень удобный язык для реализации работы в браузере (хотя работа с canvas марока еще та...)).
На основании вышесказанного, можно выделить основные требования, которые хотелось бы предъявить к языку:
- Быстродействие
- Отказоустойчивость
- Удобство
- Простота базового освоения
- Кроссплатформенность
Также еще желательно:
- ООП
- Функциональное программирование
- Единство работы в разных средах (браузер, ПК, мобильное приложение)
- Сохранение работоспособности кода для более новых версий языка
Что ж, приступаем к разработке.
Первое, с чего хочется начать мой рассказ — это кроссплатформенность. Наверно не для кого не секрет, что Java и JavaScript компилируются в байт код, а промежуточной стадией работы компилятора/интерпретатора для других языков является ассемблер. В любом случае, если вы пытаетесь сделать кроссплатформенный язык, то у него должна быть стадия компиляции, код в которой максимально приближен к машинному языку, но при этом сохраняет еще свою однообразность для разных платформ. Остается только выбрать между ассемблером и машинным байт кодом. Думаю, что тут будет приоритетнее выбрать язык ассемблера синтаксиса AT&T(см. эту статью) для дальнейшего удобства. Но и его мы немного отредактируем также под однородный стиль, получив таким образом язык у которого стилистика команд будет примерно такой:
(знаковая/беззнаковая) ; команда ; (использующиеся флаги) ; размерность операндов ; операнд 1; операнд 2; ...
Комментарий: точки с запятыми расставлены для удобства чтения, скобки обозначают необязательность параметра для некоторых команд. Про него я расскажу подробнее в следующих статьях, а пока вернемся к Ctag.
Глава 1. Привет Мир.
Синтаксис нашего языка будет не слишком отличаться от привычного С, но язык будет не полностью компилируемым (если возможно, то получаем ассемблерный код, иначе компилируем построчно (интерпретируем)...). Это связано с тем, что заставлять язык быть полностью компилируемым — значит лишить его элегантного кода в области связанной, например, с метапрограммированием.
Итак, напишем типичную первую программу:
#import print from stdio
function main() -> int(4){
print("hello world");
return 0;
}
Странная помесь, которую я пока откажусь комментировать. Примите на веру).
Глава 2. Переменные.
Тут наступает время новых откровений. Дело в том, что Сtag по примеру С# является языком двойной типизации, т.е. позволяет как статические переменные, так и динамические. Всего в языке существует более 10 базовых типов:
1) nil
2) int
3) double
4) register
5) char
6) string
7) function
8) code
9) operator
10) statment
11) bool
11) object
А также еще несколько стандартных типов, как array, set, map,… подключаемые через библиотеки. Теперь подробнее про каждый тип:
1) nil или пустой тип. По умолчанию присваивается любой переменной при объявлении. Также может быть вернут любой функцией как признак ошибки.
int a; print(a) //nil
function f() -> int(4) {return nil;} //не ошибка
2) int. Стандартный тип для работы с целыми числами. Существует две формы объявления:
- Статическая с параметром — размер.
- Динамическая.
Если в качестве параметра статического объявления стоит небольшое число(<=8), то «класс» заменяется более дешевым в плане операций эквивалентом. (вы не можете объявить переменную размера <8 не являющегося степенью 2).
int(4) a; //equal to int in C++
int(128) b; //static type int
int c; //dynamic type int
4) register. Специальный тип предназначенный для переменных с большим количеством обращений. Если в качестве имени переменной будет указано настоящее имя одного из регистров, то компилятор попытается выделить вам его. В другом случае компилятор попытается найти место наиболее близкое по скорости к регистровой памяти (регистр или кеш 1 уровня). Имеет один параметр определяющий размер регистра. По умолчанию выбирается наибольшее доступное значение.
register a; //give me some register
register ax; //give me ax
register bx; //give me rbx
5) char. Тип для хранения символа. Имеет один параметр строкового типа, который определяет кодировку символа (ASCII = 1 байт, utf-16 = 2 байта, utf-32 = 4, utf-8 = 4 всегда, для удобства индексации). По умолчанию выбирается utf-8.
char c; //the same to char(utf-8) c; sizeof(c) = 4!!!!
char(ASCII) ch;
6) string. Базовый тип, производный от char. Имеет два параметра. Первый — кодировка. Второй — размер. Оба параметра необязательны. Если не указан второй, то строка считается динамической.
string s1; //charset = utf-8; dynamic string
string(ASCII) s2; //dynamic string of ASCII characters
string(ASCII, 80) buf; //standart C string
7) function. Базовый тип для задания функций. Существуют два объекта данного типа: сырая функция и скомпилированная. Все используемые в программе функции получают этот тип. Без специальных событий не является компилируемым объектом.
function hello;
hello.code = {print("hello world");}
hello.lock() //we can't do anything with this function in future
hello.compile() //compile function(can't make this without lock)
hello.run() //it runs faster than without lock
8) code. Базовый тип реализующий сырой код. Является некомпилируемым объектом, если объявлен без спецификатора const. Смысл это типа будет показан в дальнейшем.
code a = {print(x);} //could not compile
const code b = {print(x);} //could compile
fuction print_var(int x) -> nil {b;}
9) operator. Базовый тип способный подменять разные операторы. Вокруг оператора обязательны пробельные символы.
operator op = "<";
if (a op b) ...
10) statment или выражение. Базовый тип призванный скрывать вычисление выражения. Входные данные — любые переменные. Выходной тип — bool.
statment s = (a < b);
int a =10;
int b = 15;
if (s) ...
11) object. Тип предназначенный для динамической типизации. Имеет другой способ объявления — ключевое слово var.
#import readint from stdio
#import print from stdio
function main() -> int(4){
var a, b;
a = readint();
b = readint();
print(a + b);
}
Ключевые слова и переменные
С помощью нескольких ключевых слов можно изменять видимость переменных. Их всего 3:
- global
- local
- const
1) Ключевое слово global используется для расширения области видимости переменной. Если переменная объявляется внутри функции, то делает ее глобальной переменной. Вне кода функций делает переменную полностью глобальной.
2) Ключевое слово local используется для сужения области видимости переменной. Если переменная объявляется внутри функции, то не взымает воздействия. Примененное к внешним переменным, сужает их область видимости до текущего файла.
Теперь я хотел бы закончить эту статью. Продолжение следует…
Автор: int33h