Ґенерування коду

Як і на етапі семантичного аналізу, генерування коду — це обхід всього дерева, від «листків» до «кореня», і вузли опрацьовуються залежно від назви («типу»). Отже, ми визначаємо, який саме «код» буде згенеровано для вузла кожного певного типу.

Код:

#!/usr/bin/env python
 
import spark
from helper import getValue
 
device = 'htb0'
 
root_setup = """#
#
# "%s":
tc qdisc add dev %s root handle %s: htb
tc class add dev %s parent %s classid %s htb rate %skbit ceil %skbit"""
 
class_setup = """
#
# Client "%s":
tc class add dev %s parent %s classid %s htb rate %skbit ceil %skbit"""
 
 
class Interpret(spark.GenericASTTraversal):
    def __init__(self, ast):
        spark.GenericASTTraversal.__init__(self, ast)
        self.postorder()
 
    def n_root(self, node):
        # generate code:
        handle = node.classid.attr.split(':')[0]
        node.code = root_setup % (
            getValue(node, 'descr'),
            device,
            handle,
            device,
            '%s:%s' % (handle, 0),
            node.classid,
            getValue(node, 'rate'),
            getValue(node, 'ceil') or getValue(node, 'rate')
        )
 
    def n_classdef(self, node):
        # generate code:
        node.code = class_setup % (
            getValue(node, 'descr'),
            device,
            node.parent,
            node.classid,
            getValue(node, 'rate'),
            getValue(node, 'ceil') or getValue(node, 'rate')
        )
 
    def default(self, node):
        # "default" will be called for all
        # unmentioned nodes.
        # In our case -- for "classdefs",
        # which contain other classes.
 
        # generate code:
        node.code = '\n'.join([ x.code for x in node.kids ])

Метод default буде викликано для усіх незазначених вузлів. У нашому випадку — для «classdefs» та «classes«, які містять визначення класів HTB.

І, нарешті, наша програма має такий вигляд:

#!/usr/bin/env python
 
import spark
import scanner
import parser
import semantic as semant
import generate as generat
 
def scan(f):
    input = f.read()
    scnr = scanner.SimpleScanner()
    return scnr.tokenize(input)
 
def parse(tokens):
    prsr = parser.SimpleParser()
    return prsr.parse(tokens)
 
def semantic(ast):
    semant.HTBCheckTree(ast)
    return ast
 
def generate(ast):
    generat.Interpret(ast)
    return ast
 
 
f = open('test.confg')
 
print generate(semantic(parse(scan(f)))).code

Згенерований код:

#
#
# "Root_as_root":
tc qdisc add dev htb0 root handle 1: htb
tc class add dev htb0 parent 1:0 classid 1:5 htb rate 10240 ceil 20480
 
#
# Client "My_favorite_client":
tc class add dev htb0 parent 1:5 classid 1:50 htb rate 1024kbit ceil 2048kbit
 
#
# Client "My_other_client":
tc class add dev htb0 parent 1:50 classid 1:53 htb rate 1024kbit ceil 2048kbit

*Досі* робимо помилки

Безумовно — цей приклад неповний.

Якщо ми визначимо класи у конфігураційному файлі не у тому порядку, у якому вони мають створюватися під час виконання стартового скрипта HTB — ми матимемо скрипт, який не працюватиме. Щоб мати працюючий, треба виконати більш строгі семантичні перевірки.

Напевно, якісь інші нюанси просто безглузді (і з точко зору програмування) — не зважайте :-)

І, ще раз, ми навмисно вибудували наше синтаксичне дерево саме так, пропустивши певні шматки нашого синтаксису. З метою продемонструвати можливості SPARK.

Ви можете взяти всі тексти програми з цієї статті та знайти іншу інформацію на сторінці Ресурси.

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

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

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