2013-04-16 6 views
6

मैं नई Parsec करने के लिए (और सामान्य में पारसर्स करने के लिए), और मैं इस पार्सर मैंने लिखा के साथ कुछ समस्या हो रही है:कठिनाई एक Parsec पार्सर रिक्त स्थान को छोड़ने के लिए हो रही है सही ढंग से

list = char '(' *> many (spaces *> some letter) <* spaces <* char ')' 

विचार करने के लिए है इस प्रारूप में सूचियों को पार्स (मैं s-भाव करने के लिए काम कर रहा हूँ):

import Control.Applicative 
import Text.ParserCombinators.Parsec hiding (many) 

list = char '(' *> many (spaces *> some letter) <* spaces <* char ')' 

test s = do 
    putStrLn $ "Testing " ++ show s ++ ":" 
    parseTest list s 
    putStrLn "" 

main = do 
    test "()" 
    test "(hello)" 
    test "(hello world)" 
    test "(hello world)" 
    test "(hello world)" 
    test "()" 

टी:

(firstElement secondElement thirdElement and so on) 

मैं इसे परीक्षण करने के लिए इस कोड को लिखा था उसकी है उत्पादन मैं:

Testing "()": 
[] 

Testing "(hello)": 
["hello"] 

Testing "(hello world)": 
["hello","world"] 

Testing "(hello world)": 
["hello","world"] 

Testing "(hello world)": 
parse error at (line 1, column 14): 
unexpected ")" 
expecting space or letter 

Testing "()": 
parse error at (line 1, column 3): 
unexpected ")" 
expecting space or letter 

आप देख सकते हैं, यह विफल है जब वहाँ सूची के अंतिम तत्व है, और समापन ) के बीच सफेद स्थान। मुझे समझ में नहीं आता है कि spaces द्वारा सफेद जगह का उपभोग क्यों नहीं किया जाता है, मैंने <* char ')' से पहले रखा था। मैंने क्या मूर्खतापूर्ण गलती की है?

उत्तर

12

समस्या,

list = char '(' *> many (spaces *> some letter) <* spaces <* char ')' 
        -- ^^^^^^ that one 

कि अंतिम रिक्त स्थान many को बहस में spaces द्वारा खपत होती है और फिर पार्सर some letter उम्मीद है, लेकिन एक समापन कोष्ठक पाता है और इस तरह विफल रहता है।

इसे हल करने के लिए, केवल टोकन के बाद रिक्त स्थान का उपभोग

list = char '(' *> spaces *> many (some letter <* spaces) <* char ')' 

कि वांछित के रूप में काम करता है:

$ runghc lisplists.hs 
Testing "()": 
[] 

Testing "(hello)": 
["hello"] 

Testing "(hello world)": 
["hello","world"] 

Testing "(hello world)": 
["hello","world"] 

Testing "(hello world)": 
["hello","world"] 

Testing "()": 
[] 
0

यह थोड़ा मुश्किल है। डिफ़ॉल्ट रूप से पार्स लालची हैं। आपके मामले में इसका क्या अर्थ है? जब आप (hello world) को पार्स करने का प्रयास करते हैं तो आप ( पार्सिंग से शुरू करते हैं, तो आप कुछ रिक्त स्थान और पहचानकर्ता से मेल खाने का प्रयास कर रहे हैं। तो हम यह करते हैं। कोई रिक्त स्थान नहीं है, लेकिन पहचानकर्ता है। हमारा हो गया। हम फिर से दुनिया के साथ प्रयास करें। अब हमें _) शेष मिला है। आप पार्सर (spaces *> some letter) आज़माएं। यह लालची बनाता है: इसलिए आप अंतरिक्ष से मेल खाते हैं और अब आप कुछ पत्र की उम्मीद करते हैं, लेकिन आपको इसके बजाय ) मिलते हैं। इस समय पार्सर विफल रहता है, लेकिन यह पहले से ही अंतरिक्ष का उपभोग करता है, इसलिए आप बर्बाद हो जाते हैं। आप try Combinator का उपयोग करके उलटे पांव लौटने कि यह पार्सर बना सकते हैं: try (many (spaces *> some letter))

3

समस्या यह है कि एक बार पार्सर many (spaces *> some letter) एक अंतरिक्ष यह डिफ़ॉल्ट रूप से एक और आइटम को पार्स, Parsec के बाद से करने के लिए खुद को प्रतिबद्ध देखता ही आगे एक चरित्र लग रहा है और पीछे नहीं है ।

हथौड़े समाधान बैक ट्रैकिंग सक्षम करने के लिए try उपयोग करने के लिए है, लेकिन इस तरह की समस्याओं के लिए सबसे अच्छा के रूप में Daniel's answer में देखा, प्रत्येक टोकन बजाय बस के बाद वैकल्पिक खाली स्थान के पार्स करने से परहेज कर रहे हैं।

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