Як і на етапі семантичного аналізу, генерування коду — це обхід всього дерева, від «листків» до «кореня», і вузли опрацьовуються залежно від назви («типу»). Отже, ми визначаємо, який саме «код» буде згенеровано для вузла кожного певного типу.
Код:
#!/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.
Ви можете взяти всі тексти програми з цієї статті та знайти іншу інформацію на сторінці Ресурси.