Code Auto Modifiable

  • Je pense récemment à écrire programmes auto-modificateurs , je pense que cela peut être puissant et amusant... Donc, je suis actuellement à la recherche d'un langage qui permet de modifier facilement le code du programme..

  • J'ai lu à propos de C# (comme un moyen de contourner) et la capacité de compiler et d'exécuter du code en cours d'exécution, mais c'est trop douloureux..

  • je pense aussi à assembly ... il est plus facile de changer le code en cours d'exécution mais ce n'est pas très puissant (très brut)...

pouvez-vous me suggérer un langage puissant - ou une fonctionnalité-qui prend en charge la modification du code en cours d'exécution..?

Conseils
C'est ce que je veux dire en modifiant le code en cours d'exécution:

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

Et peut-être construire une liste d'instructions:

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

Merci!

30
demandé sur skaffman 2010-06-17 01:59:09

13 réponses

Malbolge serait un bon endroit pour commencer. Chaque instruction est auto-modifiable, et c'est beaucoup de plaisir(*) à jouer avec.

(*) avertissement: peut-être pas vraiment amusant.

42
répondu David 2010-06-16 22:00:55

Je recommande vivement Lisp. Les données Lisp peuvent être lues et exécutées sous forme de code. Code Lisp peut être écrite comme données.

Il est considéré comme l'un des langages auto-modifiables canoniques.

Exemple de liste(données):

'(+ 1 2 3) 

Ou, en appelant les données comme code

(eval '(+ 1 2 3)) 

Exécute la fonction.

Vous pouvez également entrer et modifier les membres des listes à la volée.

Modifier:

J'ai écrit un programme pour générer dynamiquement un programme et de l'évaluer à la volée, puis rapportez-moi comment il a fait par rapport à une base de référence(div par 0 était le rapport habituel, ha).

20
répondu Paul Nathan 2010-06-16 22:28:01

Chaque réponse jusqu'à présent concerne la compilation reflection / runtime, mais dans les commentaires que vous avez mentionnés, vous êtes intéressé par le code auto-modificateur - code qui se modifie en mémoire.

Il N'y a aucun moyen de le faire en C#, Java, ou même (de manière portable) en C - c'est-à-dire que vous ne pouvez pas modifier le binaire chargé en mémoire en utilisant ces langages.

En général, la seule façon de le faire est avec assembly, et cela dépend fortement du processeur. En fait, il est très Système d'exploitation dépendant aussi: pour se protéger contre les virus polymorphes , la plupart des systèmes d'exploitation modernes (y compris Windows XP+, Linux et BSD) appliquent W^x , ce qui signifie que vous devez passer par quelques problèmes pour écrire des exécutables polymorphes dans ces systèmes d'exploitation, pour ceux qui le permettent du tout.

Il peut être possible, dans certains langages interprétés, que le programme modifie son propre code source pendant son exécution. Perl, Python (Tu vois ici), et chaque implémentation de Javascript que je connais ne le permet pas, cependant.

12
répondu BlueRaja - Danny Pflughoeft 2011-03-20 18:23:29

Puis-je suggérer Python , un bon langage dynamique de très haut niveau qui a une introspection riche incluse (et par exemple l'utilisation de compile, eval ou exec permet une forme de code Auto-modifiable). Un exemple très simple basé sur votre question:

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

Notez que dans l'exemple de code ci-dessus c n'est modifié dans le domaine de la fonction.

9
répondu ChristopheD 2010-06-16 22:36:28

Personnellement, je trouve assez étrange que vous trouviez l'assemblage plus facile à manipuler que C#. Je trouve encore plus étrange que vous pensiez que l'assemblage n'est pas aussi puissant: vous ne pouvez pas obtenir plus puissant que le langage machine brut. De toute façon, à chacun son/sa propre.

C # A de grands services de réflexion, mais si vous avez une aversion pour cela.. Si vous êtes vraiment à l'aise avec C ou c++, Vous pouvez toujours écrire un programme qui écrit C/C++ et l'envoie à un compilateur. Ce ne serait viable que si votre la solution ne nécessite pas un temps d'auto-réécriture rapide (de l'ordre de dizaines de secondes ou plus).

Javascript et Python supportent également la réflexion. Si vous envisagez d'apprendre un nouveau langage de programmation amusant qui est puissant mais pas très exigeant techniquement, je suggérerais Python.

8
répondu Reinderien 2010-06-16 22:06:49

Common Lisp a été conçu avec ce genre de chose à l'esprit. Vous pouvez également essayer Smalltalk , où l'utilisation de la réflexion pour modifier le code en cours d'exécution n'est pas inconnue.

Dans ces deux langages, vous êtes susceptible de remplacer une fonction entière ou une méthode entière, pas une seule ligne de code. Les méthodes Smalltalk ont tendance à être plus fines que les fonctions Lisp, ce qui peut être un bon endroit pour commencer.

7
répondu Norman Ramsey 2010-06-16 22:40:22

De nombreuses langues vous permettent deeval code à l'exécution.

  • Lisp
  • Perl
  • Python
  • PHP
  • Ruby
  • Groovy (via GroovyShell)
6
répondu Kevin Panko 2013-11-21 20:00:28

Dans les langages de haut niveau où vous compilez et exécutez du code au moment de l'exécution, ce n'est pas vraiment du code Auto-modifiable, mais du chargement de classe dynamique. En utilisant les principes d'héritage, vous pouvez remplacer une fabrique de classes et modifier le comportement de l'application au moment de l'exécution.

Ce n'est qu'en langage assembleur que vous avez vraiment une véritable auto-modification, en écrivant directement dans le segment de code. Mais il y a peu d'utilisation pratique pour cela. Si vous aimez un défi, écrivez un virus auto-cryptant, peut-être polymorphe. Ce serait amusant.

4
répondu Kenny 2014-10-23 14:11:42

J'ai écrit du code de classe Python qui vous permet d'ajouter et de supprimer de nouvelles lignes de code à l'objet, d'imprimer le code et de l'excécuter. Code de classe affiché à la fin.

Exemple: si x = = 1, le code change sa valeur en x = 2, puis supprime le bloc entier avec le conditionnel qui a vérifié cette condition.

#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]

Une fois le code créé, vous pouvez l'imprimer:

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

Sortie:

Initial Code:

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

x = 1

Exécutez le cade en appelant l'Objet: code ()

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

Sortie 2:

Code after execution:

global x, code

x = 2

Comme vous pouvez le voir, le code a changé la variable x à la valeur 2 et supprimé tout le bloc if. Cela pourrait être utile pour éviter de vérifier les conditions une fois qu'elles sont remplies. Dans la vie réelle, ce scénario de cas pourrait être géré par un système coroutine, mais cette expérience de code Auto-modifiable est juste pour le plaisir.

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
répondu Cristian Garcia 2013-12-22 20:56:35

Parfois, même si Très font rarement du code Auto-modificateur dans Ruby.

Parfois, vous avez une méthode où vous ne savez pas vraiment si les données que vous utilisez (par exemple un cache paresseux) sont correctement initialisées ou non. Donc, vous devez vérifier au début de votre méthode si les données sont correctement initialisées, puis peut-être les initialiser. Mais vous n'avez vraiment à faire cette initialisation qu'une seule fois, mais vous la vérifiez à chaque fois.

Donc, parfois j'écris un méthode qui effectue l'initialisation puis se remplace par une version qui n'inclut pas le code d'initialisation.

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

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

    @backing_store[key]
  end
end

Mais honnêtement, je ne pense pas que cela en vaut la peine. En fait, je suis gêné d'admettre que je n'ai jamais vraiment comparé pour voir si ceUn conditionnel fait réellement une différence. (Sur une implémentation Ruby moderne avec un compilateur JIT axé sur les commentaires de profil optimisant de manière agressive probablement pas.)

Notez que, selon la façon dont vous Définissez "code Auto-modificateur", cela peut ou non être ce que vous voulez. Vous remplacez une partie du programme en cours d'exécution, donc ...

EDIT: maintenant que j'y pense, cette optimisation n'a pas beaucoup de sens. L'initialisation coûteuse n'est exécutée qu'une seule fois de toute façon. La seule chose que la modification évite, est le conditionnel. Il serait préférable de prendre un exemple où le chèque lui-même est cher, mais je ne peux pas y penser un.

Cependant, j'ai pensé à un exemple cool de code Auto-modificateur: la JVM Maxine . Maxine est une machine virtuelle de recherche (techniquement, n'est pas autorisée à appeler une " JVM " parce que ses développeurs n'exécutent pas les testsuites de compatibilité) écrite complètement en Java. Maintenant, il y a beaucoup de JVM écrites en soi, mais Maxine est le seul que je connaisse aussi fonctionne en soi. C'est extrêmement puissant. Par exemple, le compilateur JIT peut se compiler adaptez - le au type de code qu'il est en train de compiler.

Une chose très similaire se produit dans la Klein VM qui est une machine virtuelle pour le langage de programmation auto.

Dans les deux cas, la machine virtuelle peut optimiser et recompiler elle-même au moment de l'exécution.

2
répondu Jörg W Mittag 2014-10-23 14:12:28

Vous pouvez le faire dans Maple (le langage d'algèbre informatique). Contrairement aux nombreuses réponses ci-dessus qui utilisent des langages compilés qui vous permettent seulement de créer et de lier dans nouveau code au moment de l'exécution, ici vous pouvez modifier honnêtement le code d'un programme en cours d'exécution. (Ruby et Lisp, comme indiqué par d'autres répondeurs, vous permettent également de le faire; probablement Smalltalk aussi).

En fait, il était standard dans Maple que la plupart des fonctions de bibliothèque étaient de petits talons qui se chargeraient leur "vrai" auto à partir du disque lors du premier appel, puis s'auto-modifier à la version chargée. Ce n'est plus le cas car le chargement de la bibliothèque a été virtualisé.

Comme d'autres l'ont indiqué: vous avez besoin d'un langage interprété avec de fortes capacités de réflexion et de réification pour y parvenir.

J'ai écrit un normalisateur/simplificateur automatisé pour le code Maple, que j'ai commencé à exécuter sur toute la bibliothèque (y compris elle-même); et parce que je n'étais pas trop prudent dans tout mon code, le normalisateur s'est modifié. J'ai également écrit un Évaluateur partiel (récemment accepté par SCP) appelé MapleMIX-disponible sur sourceforge - mais je ne pouvais pas l'appliquer complètement à lui-même (ce n'était pas l'objectif de conception).

1
répondu Jacques Carette 2010-06-17 00:28:56

Avez-vous regardé Java ? Java 6 a une API du compilateur , Vous pouvez donc écrire du code et le compiler dans la machine virtuelle Java.

0
répondu Brian Agnew 2010-06-16 22:01:58

Dans Lua , vous pouvez "accrocher" le code existant, ce qui vous permet d'attacher du code arbitraire aux appels de fonction. Il va quelque chose comme ceci:

local oldMyFunction = myFunction
myFunction = function(arg)
    if arg.blah then return oldMyFunction(arg) end
    else
        --do whatever
    end
end

Vous pouvez également simplement labourer les fonctions, ce qui vous donne du code Auto-modifiable.

0
répondu RCIX 2010-06-19 02:19:01