Вступ. Постановка задачі. Синтаксис.

Що таке SPARK?

TODO. Дивіться авторську документацію тут.

Двома словами: це інструмент (модуль Python), який дає змогу генерувати «код» з «джерельних текстів» у чотири кроки та трьома рядками:

f = open(filename)
generate(semantic(parse(scan(f))))
f.close()

Постановка задачі

Скажімо, я хочу якимось чином автоматизувати конфігурування мого шейпера (Linux, HTB). Отже, мені треба продумати синтаксис, потім «розібрати» конфігураційний файл та зґенерувати «код» (shell-скрипт для ініціалізації шейпера).

Наскільки це реальна задача? Я би сказав, реальна: адміністратор може конфігурувати шейпер як заманеться (ґрафічний інтерфейс, конфігураційні дані у SQL базі тощо), але із використаням SPARK можна створити інструмент для перевірки (валідації) конфігурації. Безумовно, можна використовувати правила та тріґґери бази даних, інші засоби інших інструментів, але все це може завершувати SPARK. Я маю на увазі, можна зчитати конфігурацію з бази, записати у текстовий файл та обробити: перевірити конфігурацію та створити код (скрипт у даному випадку).

І, звичайно, я трохи спростив синтаксис. Однак ми спробуємо, задля демонстрації ;-)

Синтаксис

Ми почнемо з такого конфігураційного файлу:

# коментарі будемо іґнорувати.
 
class 1:5 root {
    rate = 10240
    descr = Root_as_root
    ceil = 20480
}
 
class 1:50 parent 1:5 {
    ceil = 2048
    rate = 1024
    descr = My_favorite_client
}
 
class 1:53 parent 1:50 {
    descr = My_other_client
    ceil = 2048
    rate = 1024
}

Це гарний синтаксис? Чи поганий?

Зараз ми не можемо відповісти :-)

Він гарний, якщо дає змогу визначити конфігурацію для нашого завдання; тобто, зараз нам важливо визначити синтаксис для нашої «малої мови».

Після деяких роздумів та експериментів я зупинився на такому синтаксисі:

classes ::= rootdef classdefs        (1)
rootdef ::= rootclass { params }     (2)
classdefs ::= classdef               (3)
classdefs ::= classdefs classdef
classdef ::= ordclass { params }     (4)
params ::= ratedef
params ::= ceildef
params ::= descrdef
params ::= params params
ratedef ::= rate = number
ceildef ::= ceil = number
descrdef ::= descr = string
rootclass ::= class classid root
ordclass ::= class classid parent classid

Це означає:

  1. Наші класи — кореневий клас плюс решта класів («звичайних»),
  2. Визначення кореневого класу повинно містити визначення «rootclass» та набір параметрів,
  3. «Всі інші класи» — це одне чи більше визначень «classdef«…
  4. яке повинно містити «classdef» та параметри… … і так далі.

Ми будемо намагатися вибудувати AST таким чином:

       classes
          /\
         /  \
        /    \
       /      \
      /        \
   root     classdefs
               /\
              /  \
             /    \
            /      \
           /        \
      classdefs  classdef
          .
          .
          .
      classdefs
         /\
        /  \
       /    \
      /      \
     /        \
classdefs  classdef
    |
    |
    |
classdef

Видно, що наше дерево не відображає наш синтаксис, якщо чесно :-) Воно не містить вузлів «params», «ratedef» тощо. Але ми пропустили їх навмисно: SPARK дає змогу будувати дерева «як треба», пропускаючи одні вузли та «прививаючи» інші. Це питання стилю, напевно, — які вузли повинні формувати дерево для певної задачі.

(Можливо, я вибрав вузли для дерева не оптимально. Але будуємо дерево саме так, заради демонстрації SPARK, знову ж таки.)

Але це ще попереду; зараз переходимо до Сканування.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Цей сайт використовує Akismet для зменшення спаму. Дізнайтеся, як обробляються ваші дані коментарів.