Форум сайта python.su
Небольшой disclaimer:
Я не претендую на звание программиста, т.к. по образованию вообще пианист.
Просто, в процессе работы по смежной специальности, постепенно потребовалось некое программирование на быдлосредствах для чайников-музыкантов, которые хотят улучшить workflow в своем уютном закутке мира digital audio.
В настоящее время это потихоньку выливается в скромный сайд-проект под лейблом Siberian Samples (можно поискать на рутреккере), а также небольшой вклад в сообщество пользователей Cocos Reaper и NI Kontakt. Дошло дело даже до того, что в течении года я мимикрировал под кодера в более-менее состоявшейся команде Keep Forest. Правда оказалось, что профессиональная работа в программировании требует все-таки гораздо большего опыта.
Данный проект, по сути, является средством самообучения, на примере Python (в последствии для основной части деятельности планирую мигрировать в плюсы). Хочу освоится с построением архитектуры, ООП, ведением нормального репозитория и т.д. Короче, немного прокачать скиллы.
Тем не менее, учитывая в принципе неплохой стаж быдлокодера (порядка 5 лет), возможно, блог проекта будет полезен начинающим программерам, столкнувшимся с питоном. А также, поскольку я, либо в силу неграмотности, либо в силу скромности публикованных решений такого рода, либо в силу абсурдности идеи, не нашел ничего похожего на свой подход к реалиации компилятора, возможно проект будет интересен и более опытным людям
Вообще интересно. Очень часто видел фразу “каждый программист написал хоть один компилятор”, но, когда я спрашиваю совета по реализации того или иного функционала у друзей, которые не первый год живут на окладе программистов, в ответ обычно слышу что-то вроде: “знаешь, я не системщик, даже не знаю, что и сказать”.
Офлайн
LevitanusИз поста непонятно в чем вам нужна помощь.
Честно говоря, мне часто нужна помощь, которую я не знаю где искать
Отредактировано doza_and (Май 2, 2018 09:59:44)
Офлайн
doza_andНа конкретно данный момент - ни в чем
Из поста непонятно в чем вам нужна помощь.
print((var0 + 6 + 8 + var1)()) # output code: var0 + 14 + var1
@Callable def function() var0 + 6 + 8 + var1 var2.assign(5+var1+10) # output code: # var0 + 14 + var1 # var2 := 5+var1+10
class Var: def assign(arg): SingletoneOutput.send_ast(str(self.value) + ' := ' + arg)
class IOutput: ''' Singletone Interface for centralized comunication between objects. Originally designed for AST collection, but can be instantiated by: INewOutput = IOutput and be used with other purpose ''' _default = list() _output = _default def __new__(cls): return IOutput class IsSetError(Exception): pass @staticmethod def _raise_set_err(): msg = "Output can't be set now. "\ "If You want to have set"\ " functionality in some cases, use try-except block" raise IOutput.IsSetError(msg) @staticmethod def set(output): ''' redirect output of all put(data) calls to another list have to be released by release() method after all ''' if IOutput._output is not IOutput._default: IOutput._raise_set_err() IOutput._output = output @staticmethod def get(): ''' get result list ''' return IOutput._output @staticmethod def put(data): ''' put data to current output list ''' IOutput._output.append(data) @staticmethod def release(): ''' set output list to default ''' IOutput._output = IOutput._default @staticmethod def refresh(): ''' Method for resetting interface variables to defaults. Used for clearing data with multiple scrits compilation. ''' IOutput._default.clear() IOutput.release()
class Callable: ''' base decorator class for all callable objects Usage: @CallableChild # child class def func(inline=[True|False], *args, **kwargs): body child class have to have call() method overriden for assignin behaviour for calling obj without inlining of it's body ''' class MissingCallError(Exception): pass def __init__(self, func): self.func = func def __call__(self, *args, inline=False, **kwargs): if inline is True: ''' здесь переназначаем IOutput на список объекта класса-потомка''' return self.func(*args, **kwargs) ''' здесь забираем вывод от всех AST методов и inline функций в теле ''' if inline is False: return self.call(*args, **kwargs) def call(self, *args, **kwargs): ''' this method is mandatory because of inline argument mandatory. If you don't want inline definition, place return self.func(*args, **kwargs) inside the call() method ''' msg = 'call(self, *args, **kwargs) method '\ 'has to be overriden with inheritance of '\ 'Callable class' raise Callable.MissingCallError(msg)
doza_andЭто в целом есть. Дело по большей части за реализацией.
Да с описания входного языка
Отредактировано Levitanus (Май 2, 2018 10:18:30)
Офлайн
Классический компилятор - парсит вход, и строит AST. Потом проводит преобразования AST а затем генерирует текст на выходном языке.
Мне не очень понятны проблемы с формированием AST. В питоне оно получится автоматически при интерпретации кода (питон строит свой AST к которому вы кстати имеете полный программный доступ). Вам надо просто операции доопределить (__add__ и тому подобное) между своими и встроенными объектами для сложения вычитания и т.п. Дальше питон все сам сделает.
LevitanusТакое преобразование исходного кода в выходной код один в один делается в sympy можете там посмотреть как это делать. Более того, то что вы пока пишете реализуется просто в лоб средствами sympy.
var0 + 6 + 8 + var1->var0 + 14 + var1
LevitanusС Синглтоном мне не нравится решение - в самом деле свяжет вам руки. Передавать output нужно если в нем есть конфигурационная информация нужная для формирования вывода. У вас похоже ее нет. Достаточно просто возвращать результат
Но не лучше ли как-нибудь рекурсивно передавать output в кач-ве аргумента?
class Var: def assign(arg): SingletoneOutput.send_ast(str(self.value) + ' := ' + arg)
class Var: def assign(arg): return self.value + ' := ' + arg def assign1(arg): return f"{self.value}:={arg}"
LevitanusЭто для меня темный лес. Синтаксис KSP я не знаю. В чем тут проблема вообще непонятно.
Из насущного непонятного мне процесса, который в долгосрочной перспективе хотелось бы реализовать - динамическая память на синтаксисе KSP.
LevitanusОпять задам вопрос какую роль эта концепция играет в вашем языке? Если не можете сказать, то думаю оно вам не нужно.
А вот то, что в C называется куча - очень смутно.
Отредактировано doza_and (Май 2, 2018 12:53:21)
Офлайн
doza_andбезусловно. Но соль в том, что он будет не строку слать, а AST-объект.
Я бы предпочел вариант с форматированием.
doza_andИ потом польователь должен либо допилить парсер, либо просить об этом разработчика. Мне кажется, не стоит.
Классический компилятор - парсит вход, и строит AST.
doza_andВозможно. Почитаю сегодня вечером доки, спасибо!
Более того, то что вы пока пишете реализуется просто в лоб средствами sympy.
# дано:
obj1 = [int(value = 3)]
obj2 = [obj1(5), int(2)]
# в KSP
Obj_list: Obj_data_alloc: init_int:
[type, idx, size] [type, idx, size] [3]
[obj1, 0, 1] [int, 0, 1] [5]
[obj1, 1, 1] [int, 1, 1] [2]
[obj2, 2, 2] [obj1, 1, 1]
[int, 2, 1]
for obj in objects: some_var = obj.attribute
i := OBJECTS_START
while i < OBJECTS_COUNT:
select Obj_data_alloc[ Obj_list[i][idx] ][type]:
case int:
some_var := Obj_data_alloc[ Obj_list[i][idx] ][idx]
doza_andС одной стороны, возможно. С другой - в зависимости от ситуации и типа объекта воникает много всяких но и если, вплоть до того, что я почти уверен, что будут случаи, когда хотелось бы из функции получать какой-то интерпретируемый питоном результат, а не строку кода для вывода.
Достаточно просто возвращать результат
Офлайн
Levitanusвру.
И реализация простой задачи, вроде итерации по объектам с вытаскиванием параметра будет выглядеть примерно так:
i := OBJECTS_START
while i < OBJECTS_COUNT:
stack_push(Obj_data_alloc[ Obj_list[i][idx] ][type]) #это сокращение от конструкции
call get_object_type
some_var := stack_pull()
function get_object_type
select stack_pull()
case int:
stack_push(Obj_data_alloc[ Obj_list[i][idx] ][idx])
call get_int_val
case obj:
stack_push(Obj_data_alloc[ Obj_list[i][idx] ][idx])
call get_object_type()
function get_int_val
stack_push(init_int[stack_pull()])
Отредактировано Levitanus (Май 2, 2018 14:18:47)
Офлайн
Я не понял зачем ты этот язык делаешь и во что ты хочешь его компилировать, но для музыки есть Csound который можно подключить к python-у.
Офлайн
Rodegastдля самообразования
Я не понял зачем ты этот язык делаешь
Rodegastближайшая аналогия - скрипты 1С
во что ты хочешь его компилировать
Rodegastда в принципе, есть даже и менее харконые решения из уже готовых библиотек, и еще менее хардкордные
для музыки есть Csound который можно подключить к python-у.
Офлайн
doza_andкак-то пропустил я это предложение
питон строит свой AST к которому вы кстати имеете полный программный доступ
Офлайн
Levitanushttps://docs.python.org/3/library/ast.html
И как к нему получить программный доступ?
LevitanusЯ за то чтобы даже для самообразования делать полезные вещи. Поэтому и предлагаю сначала провести сравнение с аналогами и выделить вашу основную идею.
для самообразования
LevitanusНе противоречит возврату результата. Питон динамический язык. тип может определяться после возврата данных и может меняться.
хотелось бы из функции получать какой-то интерпретируемый питоном результат, а не строку кода для вывода.
LevitanusДа это хорошее предложение. Лучше так и сделать.
давайте подождем день-два? Я чуть попишу, уложу код и мысли
Офлайн