Introduction, our Task and Syntax

What is SPARK?

TODO. Read author’s paper here.

In a couple of words: a tool (a Python module), which allows to generate a «code» from a «source file», in four steps and three lines of Python code:

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

The task

Lets” suppose i want to automate configuring my shaper (Linux, HTB) in some way. So, i need to «invent» a syntax, then parse my configuration file, then check and generate «a code» (script for initializing a shaper).

Is it a «real world task»? I believe, yes: one can configure her shaper in any way (with GUI, storing configuration in SQL database, let’s say), but with SPARK it can be a tool for validating configuration. Surely, you will use rules and triggers with SQL database, other instruments with other tools, but all these ways may lead to SPARK. I mean, it’s easy to read a configuration from SQL and write in a text file, and then process it. Validate configuraion and generate a code (shell script in our case).

And, of course, i have simplified a syntax a bit. Anyway i will try it for the sake of demonstration ;-)

Syntax

We wil start with this syntax of configuration file:

# коментарі будемо іґнорувати.
 
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
}

Is it good or is it bad?

At this point we can not answer :-)

It is good if it allows to define configuration for our task; and now it is much more important to define a syntax for our «little language».

After some experiments i decided to choose this one:

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

This means:

  1. Our classes shoud consist of root class definition and all another, «ordinary» classes,
  2. Root class definition should consist of «rootclass» definition and a set of parameters,
  3. «All other classes» definition should be one or more «classdef» definitions…
  4. which is, in turn, «classdef» and parameters… … and so on.

And we will try to build AST as follows:

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

You can see that out Syntax Tree does not reflect our syntax, to be honest. It misses «params«, «ratedef» nodes etc. But we omit them intentionally: with SPARK it’s easy to build AST «as you wish», to omit some nodes and to «inject» some others. And it’s a question of style, probably, which nodes will form AST for your task.

(And, probably, i choose nodes for tree not optimally. But let tree will be as shown, for demonstration’s sake, again.)

But this will follow; now go forward to Scanning.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.