2011-12-17 5 views
5

मेरे पास एक पार्सर है जो सीधे आगे की ओर लगता है। मैं अंत करने के लिए इस उप-पार्सर जोड़ा सामान्य पार्स त्रुटियों के बारे में जानकारी देने के लिए के बाद से सभी अन्य उप पारसर्स विफल -FParsec त्रुटि को हल करने के लिए कैसे करें "संयोजक 'कई' को एक पार्सर पर लागू किया गया था जो उपभोग किए बिना सफल होता है ..."

/// Read the rest of a line as an error. 
let readError = 
    parse { 
     let! restOfLineStr = restOfLine true 
     return makeViolation ("Read error on: " + restOfLineStr + ".") } 

/// Read an expression. 
do readExprRef := 
    choice 
     [attempt readBoolean 
     attempt readCharacter 
     attempt readString 
     attempt readInt 
     attempt readError] // just now added this sub-parser, and get the issue 

हालांकि, एक बार मैं एक विकल्प के रूप में readError जोड़ने के लिए, मैं स्ट्रीम के बारे में खतरनाक FParsec त्रुटि मिलती है रन-टाइम पर खपत - The combinator 'many' was applied to a parser that succeeds without consuming input and without changing the parser state in any other way. मुझे समझ में नहीं आ रहा है कि मुझे ऐसा क्यों मिलता है क्योंकि मैं उपयोग की गई त्रुटि (यहां 'उल्लंघन') संरचना बनाने के लिए पार्स किए गए बाकी लाइन का उपयोग करता हूं।

क्या कोई इसे समझने में मेरी सहायता कर सकता है? क्या मैं गलत तरीके से उपयोगकर्ता को पार्सर त्रुटियों को सिग्नल करने जा रहा हूं? यदि नहीं, तो मैं इसे कैसे ठीक कर सकता हूं?

आपकी मदद के लिए कृपया धन्यवाद!

/// The expression structure. 
type Expr = 
| Violation of Expr 
| Boolean of bool 
| Character of char 
| String of string 
| Int of int 

/// Make a violation from a string. 
let makeViolation str = Violation (String str) 

/// Read whitespace character as a string. 
let spaceAsStr = anyOf whitespaceChars |>> fun chr -> string chr 

/// Read a line comment. 
let lineComment = pchar lineCommentChar >>. restOfLine true 

/// Read a multiline comment. 
/// TODO: make multiline comments nest. 
let multilineComment = 
    between 
     (pstring openMultilineCommentStr) 
     (pstring closeMultilineCommentStr) 
     (charsTillString closeMultilineCommentStr false System.Int32.MaxValue) 

/// Read whitespace text. 
let whitespace = lineComment <|> multilineComment <|> spaceAsStr 

/// Skip any white space characters. 
let skipWhitespace = skipMany whitespace 

/// Skip at least one white space character. 
let skipWhitespace1 = skipMany1 whitespace 

/// Read a boolean. 
let readBoolean = 
    parse { 
     do! skipWhitespace 
     let! booleanValue = readStr trueStr <|> readStr falseStr 
     return Boolean (booleanValue = trueStr) } 

/// Read a character. 
let readCharacter = 
    parse { 
     // TODO: enable reading of escaped chars 
     do! skipWhitespace 
     let! chr = between skipSingleQuote skipSingleQuote (manyChars (noneOf "\'")) 
     return Character chr.[0] } 

/// Read a string. 
let readString = 
    parse { 
     // TODO: enable reading of escaped chars 
     do! skipWhitespace 
     let! str = between skipDoubleQuote skipDoubleQuote (manyChars (noneOf "\"")) 
     return String str } 

/// Read an int. 
let readInt = 
    parse { 
     do! skipWhitespace 
     let! value = pint32 
     let! _ = opt (skipString intSuffixStr) 
     do! notFollowedByLetterOrNameChar 
     do! notFollowedByDot 
     return Int value } 

मुझे पता नहीं -

* अधिक विस्तार *

यहां कुछ और कोड है कि प्रासंगिक हो सकता है है। हो सकता है कि मुद्दा यह है कि यह पहले से ही स्ट्रीम के अंत में है जब यह readError पार्सर चलाने की कोशिश करता है। क्या यह आराम करेगा ओफलाइन कोई इनपुट नहीं लेता है, यहां तक ​​कि सफेद जगह भी नहीं?

* निष्कर्ष *

ऐसा लगता है कि दृष्टिकोण एक readError पार्सर के साथ रिपोर्टिंग गलत है त्रुटि के लिए। सही दृष्टिकोण इसलिए की तरह एक 'अंत तक' पार्सर उपयोग करने के लिए है -

/// Read the end of input. 
let readEndOfInput = skipWhitespace >>. eof 

// Read multiple exprs. 
let readExprs = many readExpr 

// Read exprs until the end of the input. 
let readExprsTillEnd = readExprs .>> readEndOfInput 

अब मैं सिर्फ readExprsTillEnd चलाने जब मैं एक इनपुट स्ट्रीम में सभी exprs प्राप्त करने की आवश्यकता।

धन्यवाद, गुस्तावो!

+0

पर एक नजर है आप और अधिक कोड पोस्ट कर सकते हैं? विशेष रूप से makeViolation समारोह का शरीर। – Gustavo

+0

हो गया। बीटीडब्ल्यू, गुस्तावो, मैं आपके ब्लॉग का एक बड़ा प्रशंसक हूं। मुझे आशा है कि डॉन सिमे आपके द्वारा किए गए काम को देख रहे हैं - एचके या टीसी के बिना मज़दूर, आवेदक और मोनैड प्राप्त करना बहुत बड़ा है! मुझे आश्चर्य है कि क्या हम आपके द्वारा कुछ रूपों में तीर भी प्राप्त कर सकते हैं;) –

+0

टाइपक्लास के साथ मेरे काम के बारे में आपकी प्रतिक्रिया के लिए धन्यवाद ब्रायन। मुझे यह भी उम्मीद है कि एफ # टीम के लोग इस तकनीक के लिए और अधिक समर्थन जोड़ सकते हैं, अन्यथा वे सीएलआर टीम पर निर्भर करते हैं ताकि वे .NET स्तर पर वास्तविक टाइपक्लास समर्थन को कार्यान्वित कर सकें। तीरों के बारे में, क्या आपने http://stackoverflow.com/questions/4034802/how-would-i-translate-a-haskell-type-class-into-f पर एक नज़र डाली है? Http://code.google.com/p/fsharp-typeclasses पर प्रोजेक्ट में तीरों के बारे में और सामान है। – Gustavo

उत्तर

1

आपके द्वारा पोस्ट किए गए अतिरिक्त कोड के लिए धन्यवाद, दुर्भाग्य से मैं त्रुटि को पुन: उत्पन्न करने में असमर्थ था। लेकिन आप अंतिम attempt को हटाने का प्रयास क्यों नहीं करते? मुझे लगता है कि यह कोई समझ नहीं आता है और शायद एक समस्या पैदा कर रहा है।

do readExprRef := 
    choice 
     [attempt readBoolean 
     attempt readCharacter 
     attempt readString 
     attempt readInt 
     readError] 

मैं एक एफपीआरसीईसी विशेषज्ञ नहीं हूं लेकिन मुझे लगता है कि किसी विकल्प का अंतिम पार्सर प्रयास नहीं होना चाहिए।

अद्यतन:

readError पार्सर भी, कोई इनपुट लेने वाली सफल होता है कुछ बिंदु पर आप एक many यह समाप्त हो जाती है कभी नहीं होगा की पैरामीटर के रूप में readExpr को कॉल किया। मेरा मतलब है अगर तुम

run (many readError) "" ;; 

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

http://www.quanttec.com/fparsec/reference/charparsers.html#members.restOfLine पर बाकी ऑफ़लाइन फ़ंक्शन विनिर्देश पर एक नज़र डालें, यह आपको इसके बारे में चेतावनी देता है।

अब आप इसे हल करने के कई तरीके हैं, लेकिन मैं कहूंगा कि आपको पार्सर त्रुटियों को संभालने के तरीके पर पुनर्विचार करना होगा।

एक बात आप कर सकते हैं readError समारोह बाहर ले और फिर जब तुम readExpr पार्सर आप इसे इस तरह

let readExprs = many readExpr .>> eof 

ऐसा करने से आप EOF लागू करने और अगर वहाँ कुछ है द्वारा नियंत्रित नहीं फोन कॉल eof से पहले पसंद में पार्सर्स, FParsec स्वचालित रूप से आपके लिए एक अच्छा त्रुटि संदेश उत्पन्न करेगा।

और तुम उस त्रुटि को संभालने के लिए चाहते हैं, http://www.quanttec.com/fparsec/users-guide/customizing-error-messages.html

+0

मैंने आखिरी 'प्रयास' हटा दिया है और यह अभी भी वही व्यवहार है :(क्या आपको बुरा लगेगा अगर मैंने आपको इस बारे में व्यक्तिगत रूप से पिंग किया है? यदि नहीं, तो कृपया मुझे अपनी संपर्क जानकारी [email protected] पर स्लाइड करें। चीयर्स! –

+0

हां, यह काम करता है! मैंने आपकी महान मदद का उपयोग करके जवाब में अंतिम समाधान परिष्कृत किया है! बहुत धन्यवाद! –

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