Язык программирования Gentee

Уважаемое сообщество, я хочу рассказать вам о языке программирования Gentee. Я уверен, что вы о нем ничего не слышали, но это не новинка. Первая рабочая версия компилятора увидела свет в 2008 году, а в конце 2010 была выпущена последняя на данный момент 3-я версия. Gentee является open source проектом и распространяется под MIT лицензией, то есть без всяких условий и ограничений. Кроме меня над компилятором, библиотеками и всей документацией работал еще один человек. В начале я хочу написать об истории возникновения языка. Начиная с 2000 года я работал над инсталляторами, в которых пользователь мог строить сценарии из определенных команд. То есть, каждая команда из параметров на форме должна была конвертироваться в код на каком-то языке, который можно было бы компилировать в байт-код и создавать исполняемый файл. Начинали с примитивного языка, но в конце концов решили сделать язык широкого применения. Основные требования были следующие: быстрый компилятор, легкая работа с Windows API, маленький размер движка виртуальной машины, лаконичный и понятный синтаксис, возможность использования компилятора и виртуальной машины из любого языка программирования. На языке C был написан компилятор в байт-код и виртуальная машина. Gentee.dll (компилятор и ВМ) занимает всего 112 КБ и может быть включена в любой проект, которому требуется встроенный язык программирования. Программа на Gentee может быть выполнена сразу после компиляции или можно создать исполняемый файл с байт-кодом и вшитой виртуальной машиной.

Краткое описание языка


Gentee имеет «C»-подобный синтаксис и будет понятен каждому, кто сталкивался с любым языком из этого семейства. Язык имеет строгую типизацию и не является ООЯП, хотя и имеет наследование типов (объектов) и поддерживает полиморфизм. Я не буду описывать синтаксис и основные возможности, я просто приведу содержание раздела Описание языка из официальной документации, а затем остановлюсь на паре интересных моментов. Я думаю, что в этом случае у вас сложится более полное представление о возможностях Gentee.

Базовые элементы языка

  • Идентификаторы
  • Числа
  • Строки
  • Двоичные данные
  • Макросы
  • Коллекции


Структура программы. Препроцессор

  • Комментарии. Замена символов
  • Команда define
  • Команда ifdef
  • Макровыражения
  • Команда include
  • Команда import
  • Команды public и private


Типы и переменные

  • Команда type
  • Наследование типов
  • Системные методы для типов
  • Команда global
  • Локальные переменные


Функции методы операции

  • Определение функции func
  • Определение метода method
  • Переопределение операций operator
  • Определение text функции
  • Свойства property
  • Команда extern
  • Подфункции subfunc
  • Возвращение переменных


Конструкции языка

  • Конструкция условия if-elif-else
  • Конструкция выбора switch
  • Конструкции цикла while и do
  • Конструкции цикла for и fornum
  • Конструкция цикла foreach
  • Инструкции return, break, continue
  • Инструкции label, goto
  • Конструкция with


Выражения и операторы

  • Арифметические операторы
  • Логические операторы
  • Операторы присваивания
  • Приведение типов
  • Поля и указатели
  • Вызов функций и методов
  • Условный оператор ?
  • Операция позднего связывания
  • Таблица приоритетов операторов


Некоторые интересные моменты


Мне нравилось программировать на С, но мне всегда не нравилось то, что я не могу просто определить в локальных переменных строку типа str, работать с ней и не думать об ее удалении при выходе из функции. При создании языка я исправил эту проблему и можно смело написать

func myfunc
{
str mystr = "This is a string"
print( mystr ) // Я понимаю, что можно написать просто print( "This is a string")
}


Это относится не только к str, но и к любым типам. Вы можете у типа опиcать методы delete и init, которые будут автоматически вызываться при создании и уничтожении переменных. Также к любому типу можно «прикрутить» обращение по индексу [i], перебор в операторе foreach, использование операций =, +, -, ==, !=, * и т.д…

Второй интересный момент — это интеграция с любым API. Если есть DLL c экспортируемыми функциями, то можно легко подключить и использовать их в вашей программе.
Например, можно написать
import "user32.dll"
{
uint ExitWindowsEx( uint, uint )
uint RegisterWindowMessageA( uint ) -> RegisterWindowMessage
}

и затем использовать ExitWindowsEx и RegisterWindowMessage как обычные функции. Такая возможность совсем не означает, что язык не может быть портирован под другие платформы. Gentee v2 имел версию под Linux, но, к сожалению, третья версия компилятора по разным причинам пока так и остается только для Windows.

Сложно было найти компромисс между простой и мощностью языка, какого-то функционала возможно не хватает, но нам не стыдно за получившийся результат. Имеется, например, text функция — это когда идет не код со строками, а любой текст с вкраплениями кода (аналог HTML с PHP кодом). Можно линковать к байт-коду любые файлы и потом обращаться к ним прямо в памяти или записывать временно на диск (полезно для используемых DLL файлов). Конечно, есть препроцессор с макросами и условной компиляцией и еще много чего.

Что дальше?


Любой язык не представляет никакого интереса без возможности его практического применения. С одной стороны, Gentee широко используется в наших программах, в дистрибутив включено более 30 библиотек (files, string, tree, dbf, sqlite, xml, COM/OLE, HTTP, FTP и т.д.), компилятор содержит встроенный оптимизатор, имеется даже визуальная студия для созданию GUI программ (но без документации), есть отладчик, разработанный одним из пользователей Gentee. C другой стороны, массового интереса к языку нет. Причины понятны — все, что касается языка создавалось на чистом энтузиазме и поэтому не хватает средств, чтобы привести его в желаемому виду. Хочется видеть версии не только для Windows. Также, можно было бы добавить новые возможности в сам язык (необязательные параметры, поддержка UTF-8 и Unicode на уровне языка). Пути для развития имеются, но даже сейчас Gentee является очень удобным языком для использования в других приложениях и в качестве подручного инструмента для быстрого создания небольших утилит.

Тем кто скажет: «Зачем нужен еще один язык программирования?» или «Чем он лучше прочих?», — пусть назовут мне другой язык с подобными возможностями, который можно использовать в программе в качестве скриптового языка и у которого компилятор и/или виртуальная машина занимает меньше 150 КБ.
Поделиться публикацией
Комментарии 56
    +24
    «пусть назовут мне другой язык с подобными возможностями, который можно использовать в программе в качестве скриптового языка и у которого компилятор и/или виртуальная машина занимает меньше 150 КБ.»

    Я могу ошибаться, но как на счет Lua?
      +5
      Тем более, что синтаксис Lua прост до минимализма, а интерпретатор занимает 50 кб.
        +6
        TinyScheme — в ту же копилку.
          +14
          Я так понимаю gentee ещё и windows-only. Так что не преимущества языка крайне сомнительны.
          +4
          Lua?

          Import — это возможность выбраться за пределы песочницы. Для встраиваемого языка не всегда допустимо.

          Есть ли возможность работать со структурами? Можно ли задавать семантику владения параметров функций?
            –4
            Хорошо, если кто-нибудь конкретно указал размер интерпретатора у Lua. Я лично сомневаюсь, что он уложится в указанные размеры.

            >Import — это возможность выбраться за пределы песочницы. Для встраиваемого языка не всегда допустимо.

            Из постановки задачи нужна была возможноcть использовать все системные возможности Windows. Этот язык не аналог JavaScript и цели у него другие. Никто не мешает программе самой генерировать код на основе введенных параметров — в этом случае пользователь вообще не будет что используется какой-то язык.

            >Есть ли возможность работать со структурами?

            Есть базовые числовые типы, все остальные типы и есть структуры — как в С.

            >Можно ли задавать семантику владения параметров функций?

            Можно по-подробнее объяснить?
              0
              50килобайт не уложатся?
                0
                Lua укладывается в 150-200KB.

                > Можно по-подробнее объяснить?

                Функция readdir возвращает указатель на статическую структуру. Её можно только читать.
                Функция malloc возвращает указатель на аллоцированную структуру. Её обязательно потом освобождать (free).

                Как эти функции задать с помощью import?
                  0
                  Когда мы используем импорт мы знаем какого типа параметры должны передаваться импортируемой функции и что она возвращает. Если у нас обе функции возвращают указатели, то возвращаемое значение будет описаваться одинаково как uint. Ответственность за корректность работы с полученными данными остается на программисте.
                  Если мы вызвали где-то импортируемый malloc, то должны вызвать соответствующий free. Другое дело, что можно ввести, например, новый тип «память» и который использует malloc и free. В этом случае переменная будет автоматически освобождать память.
                    +3
                    uint? Даже в C адресная арифметика безопаснее. Там нельзя сложить два указателя.

                    Странно для встраиваемого языка. Обычно встраивают язык из-за слабой выразительности host-языка. Тут же какой-то интерпретируемый ассемблер.
                      –2
                      Адресная арифметика по определению не безопасна. Что сложить два указателя, что добавить к указателю какое-нибудь произвольное число — чревато примерно одинаковыми последствиями. Если программист работает с адресной арифметикой, то он должен четко представлять себе, что он делает.
                        0
                        Если уж вы делаете строго типизированный язык, то могли бы обособить указатели в отдельный тип с соответствующими ограничениями. Типизацию нужно использовать по-максимуму.

                        Ну и подтипы для указателей не помешали бы. Что-то вроде такого:

                        Import {
                        subtype DIR pointer;
                        subtype dirent pointer;

                        DIR opendir(str);
                        dirent readdir(DIR);
                        closedir(DIR);
                        }

                        Указатель полученный от opendir нельзя подставить никуда кроме readdir, closedir.
              0
              > пусть назовут мне другой язык с подобными возможностями, который можно использовать в программе в качестве скриптового языка и у которого компилятор и/или виртуальная машина занимает меньше 150 КБ.

              Jim.
                +7
                В качестве дополнительного преисущества — отсутствие C-подобного синтаксиса.
                  –16
                  ИМХО отсутствие С-подобного синтаксиса — это недостаток, и серьезный.
                    +3
                    Расскажите это питону, синтаксис которого в разы превосходит си-подобный по простоте и удобству.
                      +4
                      Извините, но это спорно — мне чтобы изучать код на Python требуется сильно напрягаться — непонятно где начинаются/кончаются блоки/методы, особенно если он не влезает на экран по вертикали. Постоянно приходится скроллить, считать отступы (глазами выделить фигурные скобки гораздо легче).
                      Может это, конечно, дело привычки, но нельзя утверждать так категорично.
                        +3
                        Очень понятно, я работаю с си-подобным синтаксисом, но в питоне прекрасно ориентируюсь. При первом взгляде это не так очевидно, но он реально крут. Естественно это мое мнение, но это мнение человека который работает именно с си-подобным синтаксисом.
                          +2
                          Вот что-то, а отступы ни разу не приходилось считать. Плюс правило «код функции не должен превышать размера экрана» помогает, даже если ему не следовать буквально, а привести к «уменьшение вложенности должно происходить в том же экране где увеличение». А при большой вложенности коротких операторов код получается короче в разы и на экране помещается больше.
                            0
                            особенно если он не влезает на экран по вертикали

                            Правильно оформленный код на Python имеет строки не длиннее 79 символов.
                              0
                              Как длина строк соотносится с размером кода по вертикали?
                                +2
                                (Я всегда буду внимательнее читать комментарии.)

                                Тогда мне ваша проблема не понятна вовсе, можно скриншот или фрагмент кода?
                              +5
                              А что, есть такой ЯП, говнокод на котором оказывается легкочитаемым?
                              +2
                              В чем же например?
                                0
                                Например отсутствием скобочек =) Это избавляет от как минимум от холливара «как ставить фигурные скобки» =)
                                  +1
                                  Как раз это для меня непреемлемо — зависимость от пробелов и табуляций, нарушение принципа «свободного синтаксиса» (или как там это называется, когда пробелы не влияют ни на что и используются только как разделители).
                                  Знаете, я как-то столкнулся с тем что в какой-то makefile поставил пробел не туда, из-за этого получил кучу ошибок. Долго пытался понять в чем дело, и долго плевался когда понял.
                                  Еще пример из той же оперы — в гугловском Go жестко зафиксировали, что открывающая скобка блока должна быть на той же строке что и блок. Еще 40 лет назад это можно было бы понять, но сейчас это смотрится дико.
                                  Ну и кроме того — С-подобный синтаксис это стандарт де-факто. C, C++, C#, Java, ObjectiveC, скриптовые языки для веба… Думаю все вместе около 95% рынка будет. Это как математическая нотация. Она тоже может быть далеко не оптимальна, но вы предложите математику отказаться от значков корней и интегралов и перейти на что-то другое:)
                                  Питон кстати тоже близкий к си-подобным, хотя и своеобразный.

                                    +3
                                    Поставить в makefile/bash-скрипт пробел не туда и получить кучу проблем — происходит постоянно. Поставить в python пробел не туда и получить кучу проблем — у меня такого еще не случалось.
                        +3
                        Ввиду того, что последняя новость датируется 2010 годом, можно сделать вывод, что проект более мертв, чем жив.
                          0
                          Тем не менее язык делают свою работу и делает ее хорошо. В язык не нужно добавлять новые плюшечки каждый месяц. IDE, утилиты, документация, библиотеки — это да — требует регулярного обновления.
                          Этот пост и писался, чтобы посмотреть на критические замечания и понять, что делать дальше.
                          +2
                          Мне нравилось программировать на С, но мне всегда не нравилось то, что я не могу просто определить в локальных переменных строку типа str, работать с ней и не думать об ее удалении при выходе из функции.
                          То есть как это? В C / C++ есть локальные переменные, и память для них автоматически освобождается при выходе из области видимости.

                          string a = "hello"; // удалится
                          string *a = new string(); // останется
                          

                          Если в вашем языке используется только первый метод, как вернуть созданный объект из функции? Он не уничтожится?
                            +2
                            Даже более того:
                            void myfunc()
                            {
                                const char *mystr = "This is a string";
                                printf("%s", mystr);
                            }
                            

                            mystr нет необходимости удалять в С/C++, этот метод не ведет к утечке
                              0
                              ну так вродеж mystr и сдержимое в стеке будет жить. потому и неутечет ничего.
                                0
                                const char *myfunc()
                                {
                                    return "This is a string";
                                }
                                
                                printf("%s", myfunc());
                                


                                пфф, так тоже не утечет, эта строка лежит, как правило, в text секции бинарника, поэтому память под нее выделяется единожды при запуске
                                  0
                                  ещё б в таких случаях утекало :)
                              –2
                              Если нужно возвратить любой объект есть атрибут result в описании функции
                              func str myarr()
                              {
                              result = "This is a string"
                              }
                                –4
                                Угловые скобки выкусились

                                Если нужно возвратить любой объект есть атрибут result в описании функции
                                func str mystr<result>()
                                {
                                result = «This is a string»
                                }

                                Пример со строками — это частный случай.
                                  +2
                                  Мм… Какой интересный pascal-style возвращения результата…
                                  Извините, но в чем смысл дублирования информации — вы указываете и <result>, и возвращаемый тип str — разве второй не гарантирует автоматически первое?
                                    0
                                    Так как язык строгой типизации, то мы решили, что должен быть явно указан тип возвращаемого значения. Если тип не указан, то функция ничего не возвращает.
                                    Например в случае
                                    func str myfunc( str s1, str s2 )
                                    {
                                    return s1 += s2
                                    }

                                    мы тоже не можем отбросить возвращаемое значение, хотя компилятор и поймет, что возвращается str.
                              +2
                              пусть назовут мне другой язык с подобными возможностями, который можно использовать в программе в качестве скриптового языка и у которого компилятор и/или виртуальная машина занимает меньше 150 КБ.

                              Вся .net-платформа (для скриптов хорошо идет, скажем, boo). И подождите мне говорить про то, сколько весит фреймворк: никто же не предлагает использовать эти скрипты за пределами .net-приложений.

                              Так что оверхед на этот скриптовый язык — нулевой.
                                +2
                                > но даже сейчас Gentee является очень удобным языком для использования в других приложениях и в качестве подручного инструмента для быстрого создания небольших утилит

                                Ну если есть другие приложения — они уже на чем-то написаны, зачем добавлять еще один язык в существующущ систему?

                                А что касается быстрого написания утилит — опять же, для существующего приложения архитектура обычно и определяет, на чем писать утилиты. А для быстрого «набросать на коленке» вполне тот же bash или perl подойдут.

                                Или сегодня день такой, или я что-то не понимаю… Сначала статья про Настройка OS Inferno, как-то пинг в никуда, теперь это…
                                  0
                                  Такие языки, обычно, добавляют для обеспечения возможности писать сценарии. Не такая уж и плохая это возможность. Это просто мы с вами unix'оиды и привыкли внешним образом объединять приложения, но в Windows или просто в некоторых немодульных проектах совсем другая философия. И для них подобные языки — благо. Взять ту же Lua (она, кстати, отличается нетимизированностью, а тут предлагают строгие типы).

                                  Что же до UNIX, то на Bash набрасывать — это то ещё удовольствие (специфичный синтаксис и ограниченные возможности по структурированию; хотя, конечно, активно использую Bash). Вот какой-нибудь более продвинутый в языковом плане Shell очень бы не помешал в повседневной работе. Однако, всё продвинутое в этой области слишком сложно в сравнении с Bash, больше проблем огребёшь, чем удобства. Так что, вопрос открыт до сих пор. Про Perl не знаю, но это точно не shell.
                                  +5
                                  Правда назвать? FORTH. Tcl/Jimsh. Lua. Ну и ещё много их.
                                    –3
                                    Кроме размера вопрос еще в том, чтобы уложить ВМ и байт-код только в один .exe файл как можно меньшего размера. Мы в свое время смотрели разные языки, но такого, который удовлетворял всем условиям так и не нашли. Может плохо смотрели.
                                      +4
                                      Видимо, плохо смотрели.
                                        +3
                                        Как раз задача для Форта. Минимальный транслятор несколько килобайт буквально. Программа компилируется по мере ввода. exe-файл — дамп памяти по сути.

                                        Правда для человека, считающего Си-подобный синтаксисом хорошим для скриптовых языков, будет сложновато разобраться с синтаксисом (одна обратная бесскобочная запись выражений чего стоит)Фортом.
                                          0
                                          Форт — это, конечно, хардкор… если не сбалансируешь скобки, забанит компилятор, если не сбалансируешь стек — компилятор пропустит…
                                            0
                                            > если не сбалансируешь стек — компилятор пропустит
                                            Это из-за бестиповости. В стековом Cat строгая типизация с выводом типов и там компилятор не пропустит некорректное выражение.
                                            В Факторе стековые диаграммы обязательны и все слова проверяются компилятором.
                                            Да и вроде некоторые форт-компилеры проверяли слова, основываясь на стековой диаграмме слова.
                                      0
                                      Интересно, только вот примеров маловато (ссылка на сайте не работает)
                                        0
                                        У меня вот эта ссылка с примерами работает.
                                        http://www.gentee.ru/programming/samples/index.htm
                                        Да, примеров маловато, но кое-что можно посмотреть также в исходниках библиотек.
                                        +6
                                        Совсем не понятно — чем новый ЯП лучше C/C++.
                                        Про вопрос в конце статьи — ответ однозначен: Lua
                                          0
                                          Тут все про Lua. Я не много о другом. Что касается «delete и init» в объектах. Названия методов режут глаза. Правильней будет так:

                                          create <-> delete
                                          add/insert <-> remove
                                          init <-> finit/finalize (? так и не смог для себя найти подходящий антоним).

                                          Нужно всегда это помнить и стараться не миксовать. Спасибо за статью!

                                            –2
                                            Помню очень давно разбирался Gentee, весьма интересный язык, но весь пакет для сборки и компиляции нужно до ума доводить.
                                            P.S. Я им с переводом на украинский помогал, они мне бесплатный инстальник (всмысле, билдер инстальников) подарили :)
                                              –1
                                              TCO есть? Сборка мусора? Типизация статическая?
                                                0
                                                Что такое ТСО?
                                                Сброки мусора нет. Типизация статическая.
                                                  0
                                                  Что такое ТСО?

                                                  Tail Call Optimization.
                                                    0
                                                    Такой оптимизации нет. Есть оптимизация, когда байт-код замешается, где это возможно, на машинный код. Также есть оптимизация по размеру — выкидываются неиспользуемые функции, переменные, типы и т.д.

                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                              Самое читаемое