2011-06-30 25 views
10

Estoy creando una aplicación de interfaz gráfica de usuario que puede controlar y manipular un flujo de mensajes. Intento crear un medio simple para permitir que el usuario script una parte de esta funcionalidad y estoy buscando posibles candidatos. Inicialmente quería utilizar XML, ya que, naturalmente, puede hacerse cargo de código incrustado:Creación de un lenguaje de programación simple en Python

<if> 
    <condition> 
     <recv> 
     <MesgTypeA/> 
     </recv> 
    </condition> 
    <loop count=10> 
     <send> 
     <MesgTypeB> 
      <param1>12</param1> 
      <param2>52</param2> 
     </MesgTypeB> 
     </send> 
    </loop> 
</if> 

Para el análisis sintáctico que estaba planeando sobre el uso de elementtree y simplemente construir Estados fuera del código. La escritura y la lectura de XML no es la cosa más fácil de hacer, sobre todo porque no puedo asumir que los escritores del guión tendrán ningún tipo de experiencia. Me preguntaba si alguien tenía alguna alternativa que sea más fácil de leer/escribir y procesar en Python. Miré en JSON, pero debido a que es un guión, el orden importa.

¿Puede alguien sugerir posibles alternativas?

Gracias.

Respuesta

16

¿Qué hay de Python itself?

Por ejemplo:

>>> import code 
>>> def host_func(): 
...  print("Hello old chap!") 
... 
>>> c = code.compile_command("print(\"Script says hello!\"); host_func()") 
>>> exec(c) 
Script says hello! 
Hello old chap! 

exec de dejará ser explícito acerca de lo que desde el entorno de host que desea exponer a través de los dos parámetros opcionales locals y globals.

En este ejemplo estoy siendo explícito acerca de lo que la secuencia de comandos globales tendrán acceso a. Tenga en cuenta que puedo "crear" variables aquí, o darle otro nombre a las funciones existentes. Es un diccionario que apunta a funciones y datos.

>>> import code 
>>> def secret(): 
...  print("What?! I don't even... get out of here.") 
... 
>>> def public(): 
...  print("Hello stranger.") 
... 
>>> c = code.compile_command("secret(); public()") 

Al llamar a este con variables globales que contienen dos funciones, que apuntan de nuevo a los ya existentes da:

>>> exec(c, {"secret": secret, "public": public}) 
What?! I don't even... get out of here. 
Hello stranger. 

Ahora, cuando Omito secret, el guión ya no puede encontrarlo.

>>> exec(c, {"public": public}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<input>", line 1, in <module> 
NameError: name 'secret' is not defined 

Aquí redefino secret todos juntos:

>>> exec(c, {"public": public, "secret":lambda: print("Haha! Doppelganger.")}) 
Haha! Doppelganger. 
Hello stranger. 

Como lazyr menciones en los comentarios hay preocupaciones de seguridad. Los ejemplos anteriores permiten que la secuencia de comandos prácticamente haga lo que quiera. En algunos casos esto no es aceptable.

Hay algunas cosas que uno puede hacer para desalentarlo:

  • neutro __builtins__, sólo permiten funciones "lista blanca" incorporados.
  • hacer que sea difícil para importar módulos.

Por ejemplo, así es como se escribe la declaración import (en Py2.* Builtins es __builtins__):

>>> import builtins 
>>> def no_import(*args, **kwargs): 
...  raise ImportError("I cannot let you do that, Dave.") 
... 
>>> builtins.__import__ = no_import 
>>> import os 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in no_import 
ImportError: I cannot let you do that, Dave. 

De esto se sigue que podemos pasar nuestra propia builtins en el parámetro globales:

>>> import code 
>>> evil_code = "import os; import stat; os.chmod(\"passwords.txt\", stat.S_IROT 
H);" 
>>> compiled = code.compile_command(evil_code) 
>>> def no_import(*args, **kwargs): 
... raise ImportError("I cannot let you do that, Dave.") 
... 
>>> exec(compiled, {"__builtins__": {"__import__": no_import}}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<input>", line 1, in <module> 
    File "<stdin>", line 2, in no_import 
ImportError: I cannot let you do that, Dave. 

Una advertencia, sin embargo, esto será Bork todas las importaciones que tienen lugar después de ella. Puede ser mejor reemplazarlo con una versión que le permita importar módulos incluidos en la lista blanca.

Y, por último, no estoy seguro de que esto te proteja por completo. Alguna persona astuta puede eludirlo. Pero las infracciones más flagrantes deberían al menos desalentarse.

+0

+1 Así que superas el hito de la reputación de 5000. Tal vez debería mencionar algo sobre las preocupaciones de seguridad? 'abrir ("/importante/archivo "," w "). escribir (" cosas ")' etc. –

+0

@lazyr: Oh gracias: D ... lo celebraré con torta. Sí, estaba pensando en eso. Podría agregar un punto al respecto. – Skurmedel

+0

La pared del texto me critica por más de 400 daños. – Skurmedel

3

Python o tal vez Lisp porque la sintaxis es fácil de analizar.

5

Puede definir su propia sintaxis de lenguaje de scripting con pyparsing.

Cuestiones relacionadas