yurikaz / templates

Open templates for Galileosky clients.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

«Программы должны писаться для того, чтобы их читали люди, и лишь во вторую очередь для выполнения машиной.» — Х. Абельсон, Дж. Сассман («Структура и интерпретация компьютерных программ»)

Скриптовый язык 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) (^)
// Определяем 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; // все флаги/параметры отключены до старта

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

if (myflags & option4) ... // если option4 установлено - что-нибудь делаем

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

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

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

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

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

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

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

if (a > b)
{
	Diagnostics("true")
}

if (a > b)
{
	Diagnostics("true")
}
else
{
	Diagnostics("false")
}

if (a > b)
{
	Diagnostics("true")
}
else if (a < 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 > b) ? a : b  // если (a > b) == true, то вернёт *а*, инече *b*

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

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

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

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

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

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

Функции

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

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

myArrayFunc(buf{}, size)  // Передача массивов в функцию всегда происходит по ссылке.
{
    for(new i = 0; i < 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
}

Внешний вид кода

  • до 80% стоимости ПО приходится на поддержку
  • обычно поддержкой занимается не автор
  • соглашения улучшают читабельность кода, позволяя разработчикам и другим инженерам быстрее вникать в (чужой) код

Отступы

Используйте 4 пробела на один уровень отступа.

Максимальная длина строки

Ограничьте максимальную длину строки 79 символами.

Перенос строчек (общие принципы):

  • перенос после запятой
  • перед операторами
  • лучше использовать переносы верхнего уровня
  • необходимо выравнивать новые строки по выражению на предыдущей строке
  • если правила ведут к плохой читабельности, используется 8 пробелов
  • Каждая строка должна содержать только одно выражение

Перенос строчек – примеры

function(longExpression1, longExpression2, longExpression3,
         longExpression4, longExpression5);

var = function(longExpression1,
               func2(longExpression2,
                     longExpression3));

alpha = (aLongBooleanExpression)
        ? beta
        : gamma;

argv++; // Correct
argc--; // Correct

argv++; argc--; // AVOID!

Пустые строки

  • Перед комментарием ДОЛЖНА быть добавлена пустая строка
  • Перед объявлением функции ДОЛЖНА быть добавлена пустая строка
  • Группы функций отделять ДВУМЯ пустыми строками
  • Группы переменных и констант отделять пустой строкой

Кодировка исходного файла

Кодировка должна быть UTF-8

Скобки

  • «Внутренние» выражения сдвигаются на 1 уровень вправо
  • Открывающая "{" ставится на новой строке кода
  • Закрывающая "}" ставится на отдельной строке, выравнивается по выражению, открывающему блок
  • Скобки используются ВСЕГДА вокруг выражений, являющихся частью управляющих выражений (даже однострочных)
  • Всегда используйте скобки в длинных выражениях, это позволяет избежать проблем с приоритетом операций. Если приоритет понятен Вам, совершенно не обязательно, что он так же воспринимается другими.
if (condifion)
{
    Diagnostics(“condition is true!”);
}

if ( (a == b) && (c == d) )
{
    statements;
} 
else if (condition)
{
    statements;
} 
else
{
    statements;
}

Пробелы

  • Ключевые слова с последующей скобкой должны быть разделены пробелом
  • Пробел НЕ используется между названием функции и скобкой (параметры). Это помогает различать методы и управляющие конструкции.
  • Пробел обязателен после запятой в списке параметров
  • Все бинарные операторы (за исключением точки) должны отделяться пробелом от обоих операндов
  • Выражения, задающие цикл for, отделяются пробелами

Именование

  • Имена должны быть короткими, но «смысловыми», должны прояснять смысл их использования.
  • Имена переменных, определенных как константы записываются в верхнем регистре со словами, разделенными подчеркиванием (“_”)
const ASCII_ZERO	=	0x30;
const ASCII_ONE		=	0x31;
const ASCII_TWO		=	0x32;
const ASCII_THREE	=	0x33;
const ASCII_FOUR	=	0x34;
const ASCII_FIVE	=	0x35;
const ASCII_SIX		=	0x36;
const ASCII_SEVEN	=	0x37;
const ASCII_EIGHT	=	0x38;
const ASCII_NINE	=	0x39;

const ASCII_DOT		=	0x2E;
  • Числовые константы не должны использоваться в коде напрямую, за исключением значений -1, 0, и 1, которые часто появляются в циклах
  • Односимвольные имена должны избегаться за исключением временных переменных. Стандартные имена для них:
  • i, j, k, m and n for integers
  • c, d and e for characters

Хорошая статья по оформлению кода

About

Open templates for Galileosky clients.

License:MIT License


Languages

Language:C++ 100.0%