2011-06-17 56 views
17

我一直在玩python一段時間,並決定通過在python中編寫自定義腳本處理程序來更好地理解編程語言。到目前爲止,我已經成功地實現了一個基本的內存處理程序,並將內存地址座標掛接到屏幕上。我的問題可以這樣構成:使用非常基本的腳本實現函數

函數如何在這裏實現? goto聲明太簡單了,我想嘗試一些更困難的事情。 (編輯)最後,我希望能夠做到:

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

...在運行運行此模塊的腳本一個shell(傻了,是吧?)

# 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()) 

一個示例腳本:

mov 1 
put 104.101.108.108.111.10 
mov 0 
ref 1 
clr 0 

(編輯)我已經決定使用這個嘗試作爲靈感,並從頭開始這個項目。 (希望我會找到一些真正的時間坐下來,再次開始課程之前編碼。) 我打算在幾天內授予最佳答案 。我希望這些信息不能阻止潛在的貢獻者提交任何他們覺得對這類編碼問題有用的東西。

+0

我認爲你需要更具體一點,那就是「基本輸入/輸出功能」,但基本上它看起來像你可以做任何事情,就像你做其他事情一樣......也就是說,添加一個或多個命令到您的解釋器。 – martineau 2011-06-17 10:19:48

+0

我用一個更好(更具體)的問題替換了這個問題。 – motoku 2011-06-17 10:28:56

+0

@ Sean Pedersen如果你展示它應該如何表現(一些真實的動作測試,通過或失敗),它會更容易回答。 – DrTyrsa 2011-06-17 10:38:00

回答

3

我很努力瞭解你在問什麼。你的函數定義在哪裏給出?在腳本處理程序或腳本中?

如果在腳本處理程序中,顯而易見的解決方案是使用lambda表達式。使用您的問題f0(x, y, z):=x^2使用的示例將翻譯在:

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

如果函數的定義將被放置在腳本本身,你可以逃脫的lambdaeval表達式的組合。這裏有一個簡單的例子,我只是一起錘鍊來說明這個想法。

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() 

運行該程序的輸出:

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

但是要記住的是:

  1. 使用eval帶來了安全隱患,你應該知道的。
  2. 編寫自己的語法分析器是一個非常酷的學習體驗! :)

HTH, Mac。

2

如果您使用編譯器手冊,它會建議在調用方法時使用堆棧。這將允許您創建遞歸函數,這是一個調用其他函數的函數,並且還將變量保持在適當的範圍內。

因此,您使用一個堆棧來堆疊每個函數調用的變量,並且使用goto來轉到該函數的地址。然後使用你的堆棧來獲取函數的返回地址,以及函數被調用時變量的狀態。而已。

祝你好運!

2

不知道我是否理解你是正確的,但如果你的目標是通過做f0(x):=mov x和其他複雜的語法來定義一個函數,那麼在我看來,像你缺少的大組件是某種詞法分析和語法分析器。一旦你擺脫了「線上的第一個符號定義線條的作用」的概念,那麼你的方法line.split(" ")已經不夠了。這些都是相當複雜的工具,每一種比彙編語言更復雜的語言都需要這些工具(儘管它們可能是手工編譯的,具體取決於語言和編譯器/解釋器)。

大多數解析在兩個主要步驟它們的輸入:

1)詞法分析 - 在此步驟以 「X + 1/5」,並將其轉換成類似 「VARIABLE OPERATOR數算符NUMBER」 有意義的符號。這個步驟的輸出被用作語法分析器的輸入

2)語法解析 - 這是更復雜的,關於語法解析的最佳方法有大量的理論。這將採取上述輸入並將其解析爲可評估的樹。像:

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

我對Python中的這些類型的工具都沒有任何經驗。在C++中,我使用的唯一工具叫做flex和bison。我確定這裏的其他人在python中使用過類似的工具,並且可能會指向一些鏈接。看起來這個問題有一些:Efficient Context-Free Grammar parser, preferably Python-friendly

我試圖尋找一些關於概念的教程,但空白。由於某種原因,我的google搜索技巧今晚沒有打開。