2011-06-17 16 views
17

के साथ फ़ंक्शंस का कार्यान्वयन मैं कुछ समय के लिए अजगर के साथ खेल रहा हूं और पाइथन में एक कस्टम स्क्रिप्ट हैंडलर लिखकर प्रोग्रामिंग भाषाओं की मेरी सामान्यीकृत समझ को बेहतर बनाने का फैसला किया है। मैंने अभी तक एक बुनियादी मेमोरी हैंडलर को सफलतापूर्वक कार्यान्वित किया है और स्क्रीन पर प्रिंट करने के लिए एक मेमोरी एड्रेस समन्वयित किया है। मेरा प्रश्न इस प्रकार से देखा जा सकता है:बहुत बुनियादी स्क्रिप्टिंग

यहां कैसे कार्यान्वित किए जा सकते हैं? एक गोटो स्टेटमेंट बहुत आसान है, मैं कुछ और कठिन कोशिश करना चाहता हूं। (मूर्ख हाँ?) ...

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

एक खोल कि एक स्क्रिप्ट है कि इस मॉड्यूल चलाता चलाता में

# 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

+0

मैंने उस प्रश्न को एक बेहतर (अधिक विशिष्ट) के साथ बदल दिया। – motoku

+0

@ सेन पेडरसन यह जवाब देना आसान होगा यदि आप दिखाते हैं कि यह कैसे व्यवहार करना चाहिए (कुछ वास्तविक-क्रिया परीक्षण, पास या असफल)। – DrTyrsa

उत्तर

3

मैं जो कुछ पूछ रहा हूं उसे समझने के लिए मैं थोड़ा सा संघर्ष कर रहा हूं। आपकी फ़ंक्शन परिभाषा कहां दी जानी चाहिए? स्क्रिप्ट हैंडलर में या लिपि में?

यदि यह स्क्रिप्ट हैंडलर में है, तो स्पष्ट समाधान lambda अभिव्यक्ति का उपयोग करना होगा। उदाहरण आप सवाल f0(x, y, z):=x^2 में प्रयोग किया जाता का उपयोग में अनुवाद होगा:

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

समारोह परिभाषाओं स्क्रिप्ट अपने आप में रखा जाना है, तो आप lambda और eval भाव के संयोजन के साथ दूर हो सकता है। यहां एक त्वरित उदाहरण दिया गया है कि मैंने विचार को चित्रित करने के लिए एक साथ हमला किया।

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. अपना खुद का व्याकरण पार्सर लिखना वाकई अच्छा सीखने का अनुभव है !! :)

एचटीएच, मैक।

2

यदि आप एक कंपाइलर मैनुअल पर जाते हैं, तो यह विधियों को कॉल करते समय ढेर का उपयोग करने की सलाह देगा। इससे आप रिकर्सिव फ़ंक्शंस, एक फ़ंक्शन जो अन्य फ़ंक्शंस को कॉल कर सकते हैं, और आपको उचित दायरे में चर भी रख सकते हैं।

तो आप फ़ंक्शन के पते पर जाने के लिए goto का उपयोग करने के लिए एक स्टैक का उपयोग करें। फिर फ़ंक्शन के वापसी पते को प्राप्त करने के लिए अपने स्टैक का उपयोग करें, और फ़ंक्शन कहलाते समय चर की स्थिति का उपयोग करें। बस।

शुभकामनाएं!

+0

एक या अधिक ढेर के अतिरिक्त, कुछ सामान्य और/या विशेष प्रयोजन रजिस्ट्रार भी बहुत उपयोगी साबित हो सकते हैं। – martineau

2

सुनिश्चित नहीं है कि मैं आपको सही समझ रहा हूं, लेकिन यदि आपका लक्ष्य f0(x):=mov x और अन्य जटिल वाक्यविन्यास करके फ़ंक्शन को परिभाषित करने में सक्षम होना है, तो यह मुझे लगता है कि आपके द्वारा खोए जाने वाले बड़े घटकों की तरह कुछ ऐसा है व्याख्यात्मक विश्लेषण और व्याकरण पार्सर का। एक बार जब आप "रेखा पर पहला प्रतीक परिभाषित करते हैं कि रेखा क्या करती है" की अवधारणा से दूर हो जाती है, तो line.split(" ") की आपकी विधि अब पर्याप्त नहीं है। ये बहुत ही जटिल उपकरण हैं, और असेंबली की तुलना में हर भाषा को अधिक जटिल बनाने के लिए इन उपकरणों की आवश्यकता होती है (हालांकि उन्हें भाषा और कंपाइलर/दुभाषिया के आधार पर हाथ से बनाया जा सकता है)।

अधिकांश दो प्राथमिक चरणों में उनके आदानों पार्स:

1) शाब्दिक विश्लेषण - यह कदम लेता है "एक्स + 1/5" और "चर ऑपरेटर नंबर ऑपरेटर नंबर" की तरह सार्थक प्रतीकों में अनुवाद करता है। इस चरण से आउटपुट का उपयोग व्याकरण पार्सर

2) व्याकरण पार्सिंग - यह अधिक जटिल है, और व्याकरण पार्सिंग करने के सर्वोत्तम तरीकों पर सिद्धांत की एक बड़ी मात्रा है। यह उपरोक्त इनपुट ले जाएगा और इसे एक पेड़ में पार्स करेगा जिसका मूल्यांकन किया जा सकता है। पसंद:

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

मुझे पाइथन में इन प्रकार के किसी भी उपकरण के साथ कोई अनुभव नहीं है। सी ++ में, मेरे द्वारा उपयोग किए जाने वाले एकमात्र टूल्स को फ्लेक्स और बाइसन कहा जाता है। मुझे यकीन है कि यहां किसी और ने पाइथन में पहले इन तरह के औजारों का उपयोग किया है, और आपको कुछ लिंक पर इंगित कर सकता है।ऐसा लगता है कि इस प्रश्न में कुछ हैं: Efficient Context-Free Grammar parser, preferably Python-friendly

मैंने अवधारणाओं पर y के लिए कुछ ट्यूटोरियल खोजने की कोशिश की, लेकिन खाली हो गया। किसी कारण से, मेरे गुगल कौशल आज रात को चालू नहीं हैं।

+0

मुझे पर्याप्त विशिष्ट होने के लिए अब भयानक लग रहा है। :/इच्छित फ़ंक्शन परिभाषा 'f1 (x): = x^2' जैसी कुछ और होनी चाहिए। मुझे यहां और कोड समीक्षा पर कई सहायक और अंतर्दृष्टिपूर्ण उत्तर मिल रहे हैं। शीर्ष पायदान जवाब, Xepo। – motoku

+0

आह, अगर आप पूर्ण अभिव्यक्ति पार्सिंग करना चाहते हैं, तो आपको लगभग एक व्याकरण पार्सर की आवश्यकता होगी। पाइथन में व्याकरण पार्सर का उपयोग करके कैलकुलेटर को कार्यान्वित करने के तरीके की खोज करें, और आपको कुछ अच्छे उदाहरणों के साथ आना चाहिए। – Xepo

1

अपने व्याकरण को परिभाषित करने के लिए pyparsing का उपयोग करने पर विचार करें। examples बहुत सारे विकी पर हैं, जैसे interactive calculator

संबंधित मुद्दे