Как стать автором
Обновить

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

Скриптовый язык EasyLogic -- это специализированный простой Си подобный язык со статической типизацией применяемый для расширения возможностей контроллеров Galileosky.

Основные возможности:

  • функции для работы с портами (RS232, RS485, CAN port) и входами / выходами.

  • доступ к тегам (чтение / запись)

  • доступ к переменным графического алгоритма (чтение / запись), из которого запущен скрипт

  • доступ к глобальным переменным (только чтение)

  • работа с файлами на SD-карте

Он поддерживает написание кода в функциональном и императивном стиле.

Используемые типы данных:

  • bool

  • int32 - знаковые целые числа с диапазоном от -2 147 483 648 до 2 147 483 647

  • одномерные и многомерные массивы int32[]

  • строки символов в формате ASCII (которые хранятся как одномерные массивы символов)

Синтаксис языка программирования

Отличительные особенности от языка C:

  • не требуется добавление заголовочных файлов

  • символы ";" опциональны, за исключением случаев, когда несколько выражений записаны в одной строке

  • если тело функции состоит из одной инструкции, то опоясывающие скобки {} не обязательны

Комментарии


// однострочный комментарий

/*  многострочный
    комментарий
    */

Переменные и константы


#define CONST_5 5

const CONST_0 = 0

new var1
new var2 = 0

var1 = CONST_5
var2 = CONST_0
var1 = var2

Массивы

Индексация начинается с 0 элемента. Массив представляет собой последовательность 32-битных слов, доступ к которым осуществляется с помощью квадратных скобок []. Каждое слово состоит из 4 байтов, поэтому для сокращения использования памяти, можно использовать побайтовый доступ с помощью фигурных скобок {}, что позволяет использовать массив как последовательность байт. Так же, как и обычные переменные массив может быть объявлен как константа и/или быть инициализированным.


const PORT_BUF_SIZE = 245

new oBuf{PORT_BUF_SIZE} //Объявление массива, размером 245 байт, занимающий в памяти 245/4 => 62 элемента (32-битных слова)
new cBuf[10] //Объявление массива размером 10 элементов (32-битных слов), т.е 10*4 => 40 байт
new const fMap_fAttr[2] = [0x20000, 0x50000] //Объявление постоянного массива с его инициализацией

Примеры доступа к элементам массива:


oBuf{0} = 2          //Присвоение 0-му байту массива значения 2
oBuf[1] = 0x5028100  //Присвоение 1-му элементу того же массива значения 0x5028100, что будет эквивалентно следующим действиям:
                     //oBuf{4} = 0x05
                     //oBuf{5} = 0x02
                     //oBuf{6} = 0x81
                     //oBuf{7} = 0x00

cBuf{1} = 0x5        //Эквивалентно следующей записи(внимание, записываются сразу 4 байта): cBuf[0] = 0x00050000

Многомерные массивы - это массивы, содержащие в себе ссылки на подмассивы. Каждый подмассив может иметь разную длину. Ниже приведены примеры объявления двумерных массивов:


new a[4][3] //4 строки по 3 столбца в каждой

/*  Двумерный массив с подмассивами различной длины. 
    e[1][5] содержит букву "l", но 
    e[0][5] - недопустимый элемент, т.к 
    длина подмассива 0 равна 3 ("O", "K", "\0")
    */
new e[2][] = [ "OK", "Cancel" ]

Для определения размера массива используется оператор sizeof. Этот оператор возвращает количество элементов (32-битных слов), а не байт! Для многомерных массивов вызов данного оператора с именем массива без скобок вернёт главную размерность, со скобками - размерность подмассива:


new matrix[3][2] = { { 1, 2 }, { 3, 4 }, { 5, 6 } }

Diagnostics("%d %d", sizeof matrix, sizeof matrix[]); // В диагностике будет строка "3 2"

Операторы

Обычные скобки () - управление порядком вычисления выражения. Квадратные скобки [] применяются для индексации массива. Оператор new используется для создания переменных и массивов.

Математические операторы

  • умножение (a * b),

  • деление (a / b) - дробная часть отбрасывается,

  • сложение (a + b),

  • вычитание (a - b),

  • остаток от деления a на b (a % b).

Операторы сравнения

  • «меньше» (<)

  • «меньше или равно» (<=)

  • «больше» (>)

  • «больше или равно» (>=)

  • «равно» (==)

  • «не равно» (!=)

Логические операторы

  • «И» (&&)

  • «ИЛИ» (||)

  • «НЕ» (!) - инвертирует значение отличное от нуля в 0, а 0 в 1, true в false и на наоборот.

Битовые операторы

  • «И» (&)

  • «ИЛИ» (|)

  • «НЕ» (~)

  • исключающее ИЛИ (XOR) (^) ```cpp

// Определяем 8 отдельных битовых флагов (они могут представлять всё, что вы захотите). const option1 = 0x01; // шестнадцатеричный литерал для 0000 0001 const option2 = 0x02; // шестнадцатеричный литерал для 0000 0010 const option3 = 0x04; // шестнадцатеричный литерал для 0000 0100 const option4 = 0x08; // шестнадцатеричный литерал для 0000 1000 const option5 = 0x10; // шестнадцатеричный литерал для 0001 0000 const option6 = 0x20; // шестнадцатеричный литерал для 0010 0000 const option7 = 0x40; // шестнадцатеричный литерал для 0100 0000 const option8 = 0x80; // шестнадцатеричный литерал для 1000 0000

// Байтовое значения для хранения комбинаций из 8 возможных вариантов new myflags = 0; // все флаги/параметры отключены до старта

Чтобы узнать битовое состояние, используется побитовое И:
```cpp
if (myflags &amp; option4) ... // если option4 установлено - что-нибудь делаем

Чтобы включить биты, используется побитовое ИЛИ:

myflags |= option4; // включаем option4
myflags |= (option4 | option5); // включаем option4 и option5

Чтобы выключить биты, используется побитовое И с инвертированным литералом:

myflags &amp;= ~option4; // выключаем option4
myflags &amp;= ~(option4 | option5); // выключаем option4 и option5

Для переключения между состояниями бит, используется побитовое исключающее ИЛИ (XOR):

myflags ^= option4; // включаем или выключаем option4 
myflags ^= (option4 | option5); // изменяем состояния option4 и option5

Операторы выбора


if (a &gt; b)
{
    Diagnostics("true")
}

if (a &gt; b)
{
    Diagnostics("true")
}
else
{
    Diagnostics("false")
}

if (a &gt; b)
{
    Diagnostics("true")
}
else if (a &lt; b)
{
    Diagnostics("false")
}
else
{
    Diagnostics("equals")
}

switch (a)  // выполнится только один блок кода по порядку при совпадении искомого значения
{
    case 0, 1:  // при *а* == 0 или 1. Остальные блоки не выполнятся.
    {
        Diagnostics("true")
    }
    case 2:  // при *а* == 2
    {
        Diagnostics("false")
    }
    default:  // при любом другом значении. Остальные блоки не выполнятся.
    {
        Diagnostics("null")
    }
}

new var = (a &gt; b) ? a : b  // если (a &gt; b) == true, то вернёт *а*, инече *b*

Операторы цикла


for (new i = 0; i &lt; 10; i++)
{
    Diagnostics("%d", i)
}

new i = 0
for (; i &lt; 10; i++)
{
    Diagnostics("%d", i)
}

new j = 0
while (j &lt; 10)
{
    Diagnostics("%d", j++)
}

while(true)  // вечный цикл
{
    // code
}

while (1)  // вечный цикл
{
    // code
}

Функции

Переменные передаются в функции по значению, а массивы по ссылке. Можно передать переменную по ссылке через символ "&". Порядок объявления функции не важен. Функция может как возвращать значение (для этого используется оператор return <значение>), так и не возвращать.


//Пользовательская функция
myFunc(&amp;a, b)  //Аргумент *a* будет передан по ссылке, аргумент *b* будет передан по значению
{
    a += 2
    return a + b  //Возвращаемое значение
}

myArrayFunc(buf{}, size)  // Передача массивов в функцию всегда происходит по ссылке.
{
    for(new i = 0; i &lt; size; i++)
    {
        Diagnostics("Buf[%d] = %d", i, buf{i})
    }
}

Структура


// объявление констант
#define CONST_5 5

const CONST_0 = 0
const CONST_1 = 1

// объявление голбальных переменных
new var1 = 42
new var2 = 0

/*    Любая программа должна содержать "входную" функцию main, 
    которая будет вызвана при запуске скрипта из алгоритмов. 
    После выхода из функции main скрипт завершается и все переменные уничтожаются, 
    поэтому при необходимости сохранения данных между итерациями вызова скрипта 
    нужно использовать глобальные переменные графических алгоритмов.
    */
main()
{
    // code
}


// объявление пользовательских функций
myFunc0()
{
    // code
}

myFunc1(a)
{
    // code
}
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.