2011-08-08 22 views
7

एक स्ट्रिंग गुजर eval करने के लिए इससे पहले कि पार करने से पहले PHP कोड inputted() मुझे यकीन है कि वाक्य रचना सही है और अनुमति देने के लिए करना चाहते हैं:मान्य उपयोगकर्ता यह eval करने के लिए()

  1. दो कार्य: एक() और बी()
  2. चार ऑपरेटरों:/* - +
  3. कोष्ठक:()
  4. नंबर: 1.2, -1, 1

कैसे मैं यह कर सकता है, शायद यह पीएचपी के साथ कुछ है Tokenizer?

मैं वास्तव में एक सरल सूत्र दुभाषिया बनाने की कोशिश कर रहा हूं ताकि एक() और बी() को ln() और exp() द्वारा प्रतिस्थापित किया जा सके। मैं स्क्रैच से टोकननाइज़र और पार्सर लिखना नहीं चाहता हूं।

+0

क्या आप उन संभावित इनपुट के आदेश की परवाह करते हैं? – hoppa

+0

फ़ंक्शन का एक उदाहरण जो आप अनुमति देंगे और एक फ़ंक्शन जो पास नहीं होना चाहिए, उसे आपके प्रश्न में जोड़ा जाना चाहिए। ध्यान दें कि eval के उपयोग को हल्के से नहीं लिया जाना चाहिए। –

+2

Thats क्यों वह पहले से संदिग्ध करना चाहता है मुझे संदेह है;) – hoppa

उत्तर

2

पार्सर जनरेटर वास्तव में पहले से ही PHP के लिए लिखा गया है, और "चूने की" विशेष रूप से ठेठ "कैलकुलेटर" उदाहरण है, जो आपके "मिनी भाषा" के लिए एक स्पष्ट शुरुआती बिंदु होगा साथ आता है: http://sourceforge.net/projects/lime-php/

यह हो गया है सालों से मैंने आखिरी बार LIME के ​​साथ खेला था, लेकिन यह पहले से परिपक्व & स्थिर था।

नोट्स:

1) का उपयोग करते हुए एक पूर्ण पर पार्सर जेनरेटर आप PHP eval (परहेज का लाभ) देता है पूरी तरह से यदि आप चाहें तो - आप चूने की जो प्रभावी रूप से करने के लिए एक "eval" समारोह प्रदान करता है एक पार्सर फेंकना कर सकते हैं आपकी मिनी भाषा में लिखे गए अभिव्यक्ति (सत्यापन में बेक्ड सत्यापन के साथ)। यह आपको आवश्यकतानुसार नए कार्यों के लिए समर्थन जोड़ने की अनुमति देने का अतिरिक्त लाभ देता है।

2) ऐसा लगता है कि इस तरह के एक छोटे से काम के लिए एक पार्सर जनरेटर का उपयोग करने के लिए पहले ओवरकिल की तरह लग सकता है, लेकिन एक बार जब आप काम करने वाले उदाहरण प्राप्त कर लेंगे तो आप उन्हें प्रभावित करेंगे और उन्हें विस्तारित करना कितना आसान होगा। और यह बहुत आसान है को कम से कम एक बग-मुक्त पार्सर (यहां तक ​​कि एक "तुच्छ") लिखने में कठिनाई से कठिनाई से।

+0

@stereofrog - क्षमा करें, मैंने परिवर्तन इतिहास को गलत तरीके से पढ़ा है। लिंक कम से कम काम करना चाहिए, हालांकि, मुझे पता है कि यह पसंदीदा प्रारूप से मेल नहीं खाता है (किसी कारण से ब्रैकेट किए गए लिंक क्रोम में मेरे लिए ठीक से प्रस्तुत नहीं किए जा रहे हैं)। – Peter

0

हाँ, आपको टोकनिज़र या कुछ समान की आवश्यकता है, लेकिन यह कहानी का केवल एक हिस्सा है। एक टोकननाइज़र (जिसे आमतौर पर "लेक्सर" कहा जाता है) केवल अभिव्यक्ति के तत्वों को पढ़ और पार्स कर सकता है, लेकिन इसका पता लगाने का कोई मतलब नहीं है कि "foo() + * bar" जैसे कुछ अमान्य है। आपको दूसरे भाग की आवश्यकता है, जिसे parser कहा जाता है जो एक पेड़ (जिसे "एएसटी" कहा जाता है) में टोकन की व्यवस्था करने में सक्षम हो सकता है या ऐसा करने में विफल होने पर त्रुटि संदेश प्रदान करता है। विडंबना यह है कि, एक बार जब आपको पेड़ मिल जाए, तो "eval" की आवश्यकता नहीं है, आप सीधे पेड़ से अपनी अभिव्यक्ति का मूल्यांकन कर सकते हैं।

मैं आपको हाथ से एक पार्सर लिखने की सलाह दूंगा क्योंकि यह एक बहुत उपयोगी व्यायाम और बहुत मजेदार है। Recursive descent parsers कार्यक्रम के लिए काफी आसान हैं।

+0

मैं मानता हूं कि हाथ से एक पार्सर लिखना मजेदार है, और किसी भी गंभीर प्रोग्रामर के लिए बुनियादी प्रशिक्षण का हिस्सा है। लेकिन यदि आप "घड़ी पर" काम कर रहे हैं तो बेहतर आईएमओ एक पूर्व-बाहर निकलने वाले पार्सर जनरेटर का पुन: उपयोग करने के लिए बेहतर होगा और व्याकरण परिभाषाओं के बारे में सीखने (और साथ में) कुछ समय बचाएगा। – Peter

+0

मैं तुम्हारा बिंदु देखता हूं, लेकिन मैं विशेष रूप से पार्सर्स के मामले में असहमत हूं। सबसे पहले, भले ही आप सीखने में रुचि रखते हैं कि सामान कैसे काम करता है, आप एक पार्सर बनाने के लिए सड़क के साथ कुछ मानक गलतियां करने की संभावना रखते हैं जो यह निर्धारित करने के लिए पर्याप्त मजबूत है कि बिग बैड वेब से दी गई स्ट्रिंग को सुरक्षित रूप से PHP में पास किया जा सकता है या नहीं eval() - और हालांकि हम अज्ञानता से नापसंद करते हैं, हम कमजोर वेब अनुप्रयोगों को भी नापसंद करते हैं। दूसरा, मुझे नहीं लगता कि कुछ नया और उपयोगी सीखने के बिना एक पार्सर जनरेटर (यहां तक ​​कि सतही रूप से) का उपयोग करना संभव है, भले ही आप आखिरकार किसी अन्य दृष्टिकोण पर निर्णय ले सकें। – Peter

3

जहां तक ​​मान्यता का सवाल है तो निम्न वर्ण टोकन मान्य हैं: यदि इनपुट स्ट्रिंग इन पैटर्न के किसी भी संयोजन से मेल खाता है

operator: [/*+-] 
funcs: (a\(|b\() 
brackets: [()] 
numbers: \d+(\.\d+)? 
space: [ ] 

एक साधारण मान्यता तो जांच कर सकता है। क्योंकि funcs टोकन बहुत सटीक है और यह अन्य टोकन के साथ ज्यादा संघर्ष नहीं करता है, इस मान्यता काफी स्थिर होना चाहिए डब्ल्यू/जरूरत ओ किसी भी वाक्य रचना/व्याकरण को पहले से ही लागू करने:

केवल
$tokens = array(
    'operator' => '[/*+-]', 
    'funcs' => '(a\(|b\()', 
    'brackets' => '[()]', 
    'numbers' => '\d+(\.\d+)?', 
    'space' => '[ ]', 
); 

$pattern = ''; 
foreach($tokens as $token) 
{ 
    $pattern .= sprintf('|(?:%s)', $token); 
} 
$pattern = sprintf('~^(%s)*$~', ltrim($pattern, '|')); 

echo $pattern; 

पूरे इनपुट स्ट्रिंग के खिलाफ मेल खाता है तो टोकन आधारित पैटर्न, यह मान्य करता है।यह अभी भी वाक्य रचना गलत पीएचपी हो सकता है, आप सुनिश्चित कर सकते यह केवल निर्दिष्ट टोकन का निर्माण है डाल:

~^((?:[/*+-])|(?:(a\(|b\())|(?:[()])|(?:\d+(\.\d+)?)|(?:[ ]))*$~ 

आप पैटर्न गतिशील निर्माण है - उदाहरण के रूप में - आप बाद में अपनी भाषा टोकन संशोधित करने में सक्षम हो अधिक आसानी से।

इसके अतिरिक्त यह आपके अपने टोकनेज़र/लेक्सर का पहला कदम हो सकता है। टोकन स्ट्रीम को तब एक पार्सर पर भेज दिया जा सकता है जो इसे व्यवस्थित रूप से मान्य और व्याख्या कर सकता है। वह हिस्सा user187291 wrote about है।

वैकल्पिक रूप से एक पूर्ण लेक्सर + पार्सर लिखने के लिए, और आपको वाक्यविन्यास को सत्यापित करने की आवश्यकता है, तो आप टोकन के आधार पर अपने व्याकरण को भी बना सकते हैं और फिर इनपुट के टोकन प्रस्तुति पर रेगेक्स आधारित टोकन व्याकरण कर सकते हैं।

टोकन वे शब्द हैं जो आप अपने व्याकरण में उपयोग करते हैं। आपको टोकन में अधिक सटीक रूप से ब्रांडेसिस और फ़ंक्शन परिभाषा का वर्णन करने की आवश्यकता होगी, और टोकनज़र को अधिक स्पष्ट नियमों का पालन करना चाहिए, जो टोकन एक और टोकन को पीछे छोड़ देता है। अवधारणा another question of mine में उल्लिखित है। यह व्याकरण फॉर्मूलेशन और सिंटैक्स सत्यापन के लिए रेगेक्स का भी उपयोग करता है, लेकिन यह अभी भी पार्स नहीं करता है। आपके मामले में eval वह पार्सर होगा जिसका आप उपयोग कर रहे हैं।

+0

[php सरणी भाषा निर्माण या regexp के साथ पार्स अनुकरण करें?] (Http://stackoverflow.com/questions/3267951/simulate-php-array-language-construct-or-parse-with-regexp/3268443#3268443) – hakre

0

आप token_get_all() का उपयोग कर सकते हैं, प्रत्येक टोकन का निरीक्षण कर सकते हैं, और पहले अवैध टोकन पर निरस्त कर सकते हैं।

0

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

क्या कोई कारण है कि आप इसके बजाय जावास्क्रिप्ट 'eval' का उपयोग नहीं करते हैं?

+0

I डेटाबेस से सूत्र में कुछ डेटा प्राप्त करने की आवश्यकता है, इसलिए मैं जेएस का उपयोग नहीं कर सकता। – hidarikani

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