Язык программирования для самоизменяющегося кода? - PullRequest
31 голосов
/ 17 июня 2010
  • Я недавно думаю о написании самоизменяющихся программ , я думаю, что это может быть мощно и весело.Поэтому в настоящее время я ищу язык, который позволяет легко изменять собственный код программы.
  • Я прочитал о C # (в качестве альтернативы) и возможности компилировать и выполнять код во время выполнения,но это слишком больно.
  • Я также думаю о сборке .Там легче изменить исполняемый код, но он не очень мощный (очень сырой).

Можете ли вы предложить мощный язык или функцию, которая поддерживает изменение кода во время выполнения?

Пример

Это то, что я имею в виду, изменяя код во время выполнения:

  Start:
  a=10,b=20,c=0;
  label1: c=a+b;
  ....
  label1= c=a*b;
  goto label1;

и, возможно, строит список инструкций:

  code1.add(c=a+b);
  code1.add(c=c*(c-1));
  code1. execute();

Ответы [ 14 ]

44 голосов
/ 17 июня 2010

Malbolge было бы хорошим началом. Каждая инструкция является самоизменяющейся, и с ней очень весело (*) играть.

(*) Отказ от ответственности: На самом деле не может быть весело.

22 голосов
/ 17 июня 2010

Я очень рекомендую Лисп. Данные о Лиспе могут быть прочитаны и исполнены как код. Лисп-код можно записать как данные.

Считается одним из канонических самоизменяемых языков.

Пример списка (данных):

'(+ 1 2 3) 

или, вызывая данные как код

(eval '(+ 1 2 3)) 

запускает функцию +.

Вы также можете входить и редактировать членов списков на лету.

редактирование:

Я написал программу для динамической генерации программы и ее оценки на лету, а затем доложил мне, как она работала по сравнению с базовой линией (обычный отчет, деленный на 0, га).

14 голосов
/ 17 июня 2010

До сих пор каждый ответ касался компиляции отражения / времени выполнения, но в упомянутых вами комментариях вас интересует фактический самоизменяющийся код - код, который изменяет себя в памяти.

Нет никакого способа сделать это в C #, Java или даже (переносимо) в C - то есть вы не можете изменять загруженный двоичный файл в памяти, используя эти языки.

В общем, единственный способ сделать это - сборка, и она сильно зависит от процессора. Фактически, она также сильно зависит от операционной системы: для защиты от полиморфных вирусов , большинства современных операционных систем (включая Windows XP +, Linux и BSD) принудительного применения W ^ X , то есть вы должны пройти через какую-то проблему , чтобы написать полиморфные исполняемые файлы в этих операционных системах, для тех, которые вообще это допускают.

Возможно, на некоторых интерпретируемых языках программа может изменить свой собственный исходный код во время работы. Perl, Python (см. здесь ) , и все известные мне реализации Javascript не допускают этого.

9 голосов
/ 17 июня 2010

Могу ли я предложить Python , хороший динамический язык очень высокого уровня, который включает в себя богатый самоанализ (и, например, использование compile, eval или exec допускает форму самоконтролямодифицирующий код).Очень простой пример, основанный на вашем вопросе:

def label1(a,b,c):
    c=a+b
    return c

a,b,c=10,20,0    
print label1(a,b,c) # prints 30

newdef= \
"""
def label1(a,b,c):
    c=a*b
    return c
"""
exec(newdef,globals(),globals())

print label1(a,b,c) # prints 200

Обратите внимание, что в приведенном выше примере кода c изменяется только в области действия функции.

9 голосов
/ 17 июня 2010

Лично я нахожу довольно странным, что вы находите сборку проще в обращении, чем C #. Мне кажется еще более странным, что вы думаете, что сборка не такая мощная: вы не можете получить ничего более мощного, чем необработанный машинный язык. Во всяком случае, каждому свое.

C # имеет отличные сервисы отражения, но если у вас есть отвращение к этому .. Если вы действительно знакомы с C или C ++, вы всегда можете написать программу, которая пишет C / C ++ и выдает ее компилятору. Это было бы жизнеспособным, только если ваше решение не требует быстрого перезаписывания времени перезаписи (порядка десятков секунд и более).

Javascript и Python также поддерживают рефлексию. Если вы хотите изучать новый, интересный язык программирования, мощный, но не требующий больших технических затрат, я бы предложил Python.

7 голосов
/ 17 июня 2010

Common Lisp был разработан с учетом этого. Вы также можете попробовать Smalltalk , где использование отражения для изменения выполняемого кода не является неизвестным.

В обоих этих языках вы, вероятно, будете заменять целую функцию или весь метод, а не одну строку кода. Методы Smalltalk, как правило, более детализированы, чем функции Lisp, так что это может быть хорошим началом.

6 голосов
/ 17 июня 2010

Многие языки позволяют вам eval код во время выполнения.

  • Лисп
  • Perl
  • Python
  • PHP
  • рубин
  • Groovy (через GroovyShell)
4 голосов
/ 17 июня 2010

В высокоуровневых языках, где вы компилируете и выполняете код во время выполнения, это на самом деле не самоизменяющийся код, а динамическая загрузка классов. Используя принципы наследования, вы можете заменить класс Factory и изменить поведение приложения во время выполнения.

Только на ассемблере у вас действительно есть истинная само-модификация, записывая непосредственно в сегмент кода. Но для этого мало практического применения. Если вам нравится вызов, напишите самошифрующийся, возможно, полиморфный вирус. Это было бы весело.

2 голосов
/ 23 декабря 2013

Я написал код класса Python, который позволяет добавлять и удалять новые строки кода в объекте, печатать код и выполнять его. Код класса показан в конце.

Пример: если x == 1, код меняет свое значение на x = 2, а затем удаляет весь блок с условным условием, проверенным для этого условия.

#Initialize Variables
x = 1

#Create Code
code = Code()
code + 'global x, code' #Adds a new Code instance code[0] with this line of code => internally             code.subcode[0]
code + "if x == 1:"     #Adds a new Code instance code[1] with this line of code => internally code.subcode[1]
code[1] + "x = 2"       #Adds a new Code instance 0 under code[1] with this line of code => internally code.subcode[1].subcode[0]
code[1] + "del code[1]" #Adds a new Code instance 0 under code[1] with this line of code => internally code.subcode[1].subcode[1]

После создания кода вы можете распечатать его:

#Prints
print "Initial Code:"
print code
print "x = " + str(x)

Выход:

Initial Code:

global x, code
if x == 1:
    x = 2
    del code[1]

x = 1

Выполнить кейд, вызвав объект: code ()

print "Code after execution:"
code() #Executes code
print code
print "x = " + str(x)

Выход 2:

Code after execution:

global x, code

x = 2

Как видите, код изменил переменную x на значение 2 и удалил весь блок if. Это может быть полезно, чтобы избежать проверки условий после их выполнения. В реальной жизни этот сценарий может быть обработан системой сопрограмм, но этот эксперимент с самоизменяющимся кодом просто для удовольствия.

class Code:

    def __init__(self,line = '',indent = -1):

        if indent < -1:
            raise NameError('Invalid {} indent'.format(indent))

        self.strindent = ''
        for i in xrange(indent):
            self.strindent = '    ' + self.strindent

        self.strsubindent = '    ' + self.strindent

        self.line = line
        self.subcode = []
        self.indent = indent


    def __add__(self,other):

        if other.__class__ is str:
            other_code = Code(other,self.indent+1)
            self.subcode.append(other_code)
            return self

        elif other.__class__ is Code:
            self.subcode.append(other)
            return self

    def __sub__(self,other):

        if other.__class__ is str:
            for code in self.subcode:
                if code.line == other:
                    self.subcode.remove(code)
                    return self


        elif other.__class__ is Code:
            self.subcode.remove(other)


    def __repr__(self):
        rep = self.strindent + self.line + '\n'
        for code in self.subcode: rep += code.__repr__()
        return rep

    def __call__(self):
        print 'executing code'
        exec(self.__repr__())
        return self.__repr__()


    def __getitem__(self,key):
        if key.__class__ is str:
                for code in self.subcode:
                    if code.line is key:
                        return code
        elif key.__class__ is int:
            return self.subcode[key]

    def __delitem__(self,key):
        if key.__class__ is str:
            for i in range(len(self.subcode)):
                code = self.subcode[i]
                if code.line is key:
                    del self.subcode[i]
        elif key.__class__ is int:
            del self.subcode[key]
2 голосов
/ 17 июня 2010

Я иногда, хотя очень редко делаю самоизменяющийся код в Ruby.

Иногда у вас есть метод, в котором вы на самом деле не знаете, правильно ли инициализируются используемые вами данные (например, ленивый кеш) или нет. Итак, вы должны проверить в начале вашего метода, правильно ли инициализированы данные, а затем, возможно, инициализировать их. Но вам действительно нужно выполнить эту инициализацию только один раз, но вы проверяете ее каждый раз.

Итак, иногда я пишу метод, который выполняет инициализацию, а затем заменяет себя версией, не содержащей код инициализации.

class Cache
  def [](key)
    @backing_store ||= self.expensive_initialization

    def [](key)
      @backing_store[key]
    end

    @backing_store[key]
  end
end

Но, честно говоря, я не думаю, что это того стоит. На самом деле, мне стыдно признать, что я никогда не проводил сравнительный анализ, чтобы понять, действительно ли это условное условие 1010 * one имеет какое-либо значение. (В современной реализации Ruby с агрессивно оптимизирующим JIT-компилятором, управляемым обратной связью, вероятно, нет.)

Обратите внимание, что в зависимости от того, как вы определяете"самоизменяющийся код", это может быть, а может и не быть тем, что вы хотите. Вы заменяете часть выполняемой в данный момент программы, поэтому & hellip;

РЕДАКТИРОВАТЬ: Теперь, когда я думаю об этом, оптимизация не имеет особого смысла. В любом случае дорогая инициализация выполняется только один раз. Единственное, чего избегает модификация, это условно. Было бы лучше взять пример, где сам чек стоит дорого, но я не могу вспомнить ни одного.

Однако я подумал о замечательном примере самоизменяющегося кода: Maxine JVM . Maxine - это исследовательская виртуальная машина (технически не разрешено называть «JVM», поскольку ее разработчики не запускают тесты совместимости), полностью написанные на Java. Теперь, есть много JVM, написанных сами по себе, но Максин - единственная, о которой я знаю, что запускает сама по себе. Это очень сильно. Например, JIT-компилятор может JIT-компилировать себя, чтобы адаптировать его к типу кода, который JIT-компилирует.

Очень похожая вещь происходит в Klein VM , которая является виртуальной машиной для языка самопрограммирования.

В обоих случаях виртуальная машина может оптимизировать и перекомпилировать сама во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...