2011-06-17 14 views
17

He estado jugando con python durante algún tiempo y he decidido mejorar mi comprensión generalizada de los lenguajes de programación escribiendo un controlador de scripts personalizado en python. Hasta ahora he implementado con éxito un manejador de memoria básico y enganché una dirección de memoria ordenada para imprimir en la pantalla. Mi pregunta puede formularse como:Implementación de funciones con scripting muy básico

¿Cómo se pueden implementar las funciones aquí? Una declaración goto es demasiado fácil, me gustaría intentar algo más difícil. (Editar) Finalmente Quiero ser capaz de hacer:

f0(x, y, z):=ax^by^cz 

... en una cáscara que ejecuta un script que se ejecuta este módulo (tonto, ¿eh?)

# notes: separate addresses from data lest the loop of doom cometh 

class Interpreter: 

    def __init__(self): 
    self.memory = { } 
    self.dictionary = {"mov" : self.mov, 
         "put" : self.put, 
         "add" : self.add, 
         "sub" : self.sub, 
         "clr" : self.clr, 
         "cpy" : self.cpy, 
         "ref" : self.ref } 
    self.hooks = {self.val("0") : self.out } 

    def interpret(self, line): 
    x = line.split(" ") 
    vals = tuple(self.val(y) for y in x[1:]) 
    dereferenced = [] 
    keys_only = tuple(key for key in self.memory) 
    for val in vals: 
     while val in self.memory: val = self.memory[val] 
     dereferenced.append(val) 
    vals = tuple(y for y in dereferenced) 
    self.dictionary[x[0]](vals) 

    def val(self, x): 
    return tuple(int(y) for y in str(x).split(".")) 

    def mov(self, value): 
    self.ptr = value[0] 

    def put(self, value): 
    self.memory[self.ptr] = value[0] 

    def clr(self, value): 
    if self.ptr in self.hooks and self.ptr in self.memory: 
     x = self.hooks[self.ptr] 
     y = self.memory[self.ptr] 
     for z in y: x(z) 
    del self.memory[self.ptr] 

    def add(self, values): 
    self.put(self.mat(values, lambda x, y: x + y)) 

    def sub(self, values): 
    self.put(self.mat(values, lambda x, y: x - y)) 

    def mat(self, values, op): 
    a, b = self.memory[values[0]], self.memory[values[1]] 
    if len(a) > len(b): a, b = b, a 
    c = [op(a[x], b[x]) for x in xrange(len(b))] + [x for x in a[len(a):]] 
    return [tuple(x for x in c)] 

    def cpy(self, value): 
    self.put(value) 

    def out(self, x): 
    print chr(x), 

    def ref(self, x): 
    self.put(x) 

interp = Interpreter() 
for x in file(__file__.split('/')[-1].split(".")[-2] + ".why"): 
    interp.interpret(x.strip()) 

un script de ejemplo:

mov 1 
put 104.101.108.108.111.10 
mov 0 
ref 1 
clr 0 

(EDIT) He tomado la decisión de utilizar este intento como inspiración y comenzar de cero en este proyecto. (Espero encontrar algún tiempo real para sentarse y programar antes de que las clases comiencen de nuevo.) Tengo la intención de otorgar la mejor respuesta en unos pocos días . Espero que esa información no disuada a los contribuyentes potenciales de enviar algo que consideren útil para este tipo de problema de codificación.

+0

Creo que debe ser más específico que simplemente "funciones básicas de entrada/salida", pero básicamente parece que podría hacer lo que sea de la misma manera que ha hecho todo lo demás ... es decir. agregue uno o más comandos a su intérprete. – martineau

+0

Reemplacé esa pregunta con una mejor (más específica). – motoku

+0

@Sean Pedersen Será más fácil responder si muestra cómo debe comportarse (algunas pruebas de acción real, aprobadas o fallidas). – DrTyrsa

Respuesta

3

Estoy luchando un poco para entender lo que está preguntando. ¿Dónde se da la definición de su función? En el controlador de scripts o en el script?

Si está en el controlador de secuencia de comandos, la solución obvia sería utilizar la expresión lambda. Usando el ejemplo que utilizó en la cuestión f0(x, y, z):=x^2 se traduciría en:

>>> f0 = lambda x, y, z : x**2 
>>> f0(2,3,4) 
4 

Si las definiciones de funciones se van a colocar en el mismo script, podría salirse con una combinación de lambda y eval expresiones. Aquí hay un ejemplo rápido que acabo de unir para ilustrar la idea.

class ScriptParser(object): 

    # See 'to_python' to check out what this does 
    mapping = {'^':'**', '!':' not ', '&':' and '} 

    def to_python(self, calc): 
     ''' 
     Parse the calculation syntax from the script grammar to the python one. 
     This could be grown to a more complex parser, if needed. For now it will 
     simply assume any operator as defined in the grammar used for the script 
     has an equivalent in python. 
     ''' 
     for k, v in self.mapping.items(): 
      calc = calc.replace(k, v) 
     return calc 

    def feed(self, lfs): 
     ''' 
     Parse a line of the script containing a function defintion 
     ''' 
     signature, calc = lfs.split(':=') 
     funcname, variables = [s.strip() for s in signature.split('(')] 
     # as we stripped the strings, it's now safe to do...' 
     variables = variables[:-1] 
     setattr(self, funcname, 
       eval('lambda ' + variables + ' : ' + self.to_python(calc))) 

def main(): 
    lines = ['f0(x, y, z) := x^2', 
      'f1(x) := x**2 + x**3 + x*1000'] 
    sp = ScriptParser() 
    for line in lines: 
     sp.feed(line) 
     print('Script definition : %s' % line) 
    for i in range(5): 
     res0 = sp.f0(i, None, None) 
     res1 = sp.f1(i) 
     print('f0(%d) = %d' % (i, res0)) 
     print('f1(%d) = %d' % (i, res1)) 
     print('--------') 

if __name__ == '__main__': 
    main() 

de ejecutar este programa salidas:

Script definition : f0(x, y, z) := x^2 
Script definition : f1(x) := x**2 + x**3 + x*1000 
f0(0) = 0 
f1(0) = 0 
-------- 
f0(1) = 1 
f1(1) = 1002 
-------- 
f0(2) = 4 
f1(2) = 2012 
-------- 
f0(3) = 9 
f1(3) = 3036 
-------- 
f0(4) = 16 
f1(4) = 4080 
-------- 

tener en cuenta sin embargo que:

  1. Uso de eval tiene implicaciones de seguridad que se deben tener en cuenta.
  2. ¡Escribir su propio analizador gramatical es una experiencia de aprendizaje realmente genial! :)

HTH, Mac.

2

Si va a un manual del compilador, le aconsejará usar pilas cuando llame a métodos. Eso le permitirá crear funciones recursivas, una función que llama a otras funciones y también mantener las variables en el ámbito adecuado.

Así que utiliza una pila para apilar sus variables para cada llamada a función, y sí, use goto para ir a la dirección de la función. Luego use su pila para obtener la dirección de retorno de la función y el estado de las variables cuando se llamó a la función. Eso es.

¡Buena suerte!

+0

Además de una o más acumulaciones, algunos registros generales y/o especiales también podrían resultar muy útiles. – martineau

2

No estoy seguro si estoy entendiendo bien, pero si su objetivo es ser capaz de definir una función haciendo f0(x):=mov x y otras sintaxis complejas, entonces me parece que los componentes grandes que falta son de algún tipo de análisis léxico y un analizador gramatical. Una vez que se aleja del concepto de "primer símbolo en la línea define lo que hace la línea", entonces su método de line.split(" ") ya no es suficiente. Estas son herramientas bastante complejas, y cada lenguaje más complejo que el ensamblaje requiere estas herramientas (aunque pueden construirse a mano, dependiendo del idioma y del compilador/intérprete).

mayoría analizar sus entradas en dos pasos principales:

1) Análisis léxico - Este paso toma "x + 1/5" y la traduce en símbolos significativos como "número de operador número de operador VARIABLE". La salida de este paso se usa como entrada para el analizador gramatical

2) Análisis gramatical: es más complejo, y hay una gran cantidad de teoría sobre las mejores formas de realizar el análisis gramatical. Esto tomará la entrada anterior y la analizará en un árbol que se puede evaluar. Me gusta:

Operator+ 
|  | 
|  ----Variable x 
Operator/ 
| | 
1 5 

No tengo ninguna experiencia con ninguno de estos tipos de herramientas en Python. En C++, las únicas herramientas que he usado se llaman flex y bison. Estoy seguro de que alguien más aquí ha usado herramientas como estas en Python, y podría indicarle algunos enlaces.Parece que esta pregunta tiene algunos: Efficient Context-Free Grammar parser, preferably Python-friendly

Intenté buscar algunos tutoriales sobre los conceptos, pero aparecieron en blanco. Mis habilidades de google no están activadas esta noche, por alguna razón.

+0

Me siento terrible ahora por no ser lo suficientemente específico. :/La definición de función prevista debe ser algo más parecido a 'f1 (x): = x^2'. He estado recibiendo numerosas respuestas útiles y perspicaces aquí y en la Revisión de código. Respuesta de primer nivel, Xepo. – motoku

+0

Ah, si quieres hacer un análisis completo de la expresión, casi definitivamente necesitarás un analizador gramatical. Haga una búsqueda de cómo implementar una calculadora usando un analizador gramatical en python, y debe encontrar algunos buenos ejemplos. – Xepo

Cuestiones relacionadas