2011-11-21 13 views
23

मैं एक साधारण कार्यात्मक भाषा के लिए एक पार्सर बनाने की कोशिश कर रहा हूं, कैमल की तरह थोड़ा, लेकिन मुझे सबसे सरल चीजों से अटक जाना प्रतीत होता है।पारसी के साथ पूर्ण पार्सर उदाहरण?

तो मैं जानना चाहता हूं कि parsec पार्सर्स के कुछ और पूर्ण उदाहरण हैं, जो कुछ है "यह है कि आप 2 + 3 कैसे पार्स करते हैं"। विशेष रूप से शब्दों और इस तरह के कॉल में काम करते हैं।

और मैंने "आपको एक योजना लिखें" पढ़ा है, लेकिन योजना का वाक्यविन्यास काफी सरल है और वास्तव में सीखने में मदद नहीं करता है।

expr = choice [number, call, ident] 

number = liftM Number float <?> "Number" 

ident = liftM Identifier identifier <?> "Identifier" 

call = do 
    name <- identifier 
    args <- parens $ commaSep expr 
    return $ FuncCall name args 
    <?> "Function call" 

:

मैं सबसे समस्याओं try, <|> और choice उपयोग करने के लिए कैसे ठीक है, क्योंकि मैं सच में नहीं मिलता है क्यों पारसेक इस पार्सर का उपयोग कर एक समारोह कॉल के रूप में a(6) पार्स करने के लिए लगता है कभी नहीं है संपादित करें, पूरा करने के लिए कुछ कोड जोड़ा गया है, हालांकि यह वास्तव में बात यह है कि मैंने पूछा नहीं है:

AST.hs

module AST where 

data AST 
    = Number Double 
    | Identifier String 
    | Operation BinOp AST AST 
    | FuncCall String [AST] 
    deriving (Show, Eq) 

data BinOp = Plus | Minus | Mul | Div 
    deriving (Show, Eq, Enum) 

Lexer.hs

module Lexer (
      identifier, reserved, operator, reservedOp, charLiteral, stringLiteral, 
      natural, integer, float, naturalOrFloat, decimal, hexadecimal, octal, 
      symbol, lexeme, whiteSpace, parens, braces, angles, brackets, semi, 
      comma, colon, dot, semiSep, semiSep1, commaSep, commaSep1 
    ) where 

import Text.Parsec 
import qualified Text.Parsec.Token as P 
import Text.Parsec.Language (haskellStyle) 

lexer = P.makeTokenParser haskellStyle 

identifier = P.identifier lexer 
reserved = P.reserved lexer 
operator = P.operator lexer 
reservedOp = P.reservedOp lexer 
charLiteral = P.charLiteral lexer 
stringLiteral = P.stringLiteral lexer 
natural = P.natural lexer 
integer = P.integer lexer 
float = P.float lexer 
naturalOrFloat = P.naturalOrFloat lexer 
decimal = P.decimal lexer 
hexadecimal = P.hexadecimal lexer 
octal = P.octal lexer 
symbol = P.symbol lexer 
lexeme = P.lexeme lexer 
whiteSpace = P.whiteSpace lexer 
parens = P.parens lexer 
braces = P.braces lexer 
angles = P.angles lexer 
brackets = P.brackets lexer 
semi = P.semi lexer 
comma = P.comma lexer 
colon = P.colon lexer 
dot = P.dot lexer 
semiSep = P.semiSep lexer 
semiSep1 = P.semiSep1 lexer 
commaSep = P.commaSep lexer 
commaSep1 = P.commaSep1 lexer 

Parser.hs

module Parser where 

import Control.Monad (liftM) 
import Text.Parsec 
import Text.Parsec.String (Parser) 
import Lexer 
import AST 

expr = number <|> callOrIdent 

number = liftM Number float <?> "Number" 

callOrIdent = do 
    name <- identifier 
    liftM (FuncCall name) (parens $ commaSep expr) <|> return (Identifier name) 
+0

विशिष्ट प्रश्न का उत्तर देना आसान होना चाहिए, लेकिन मैं आपकी समस्या का प्रदर्शन करने वाले पूर्ण, संकलित कोड नमूने के साथ प्रयास करना पसंद करूंगा ... क्या आप एक प्रदान कर सकते हैं? – sclv

+0

मुझे लगता है कि, आप कहीं भी 'try' का उपयोग नहीं करते हैं। आपके न्यूनतम उदाहरण में, मुझे यकीन नहीं है कि यह महत्वपूर्ण है, लेकिन किसी बड़े नमूने में यह निश्चित रूप से होगा। – sclv

+0

अब तक मेरा पूरा कार्यक्रम प्रदान करने की कोशिश कर रहा है। – Lanbo

उत्तर

10

हम्म,

*Expr> parse expr "" "a(6)" 
Right (FuncCall "a" [Number 6.0]) 

कि हिस्सा गायब टुकड़े भरने के बाद मेरे लिए काम करता है।

संपादित करें: मैंने अपना खुद का float पार्सर लिखकर लापता टुकड़े भर दिए, जो पूर्णांक अक्षर का विश्लेषण कर सकता था। float दूसरी ओर Text.Parsec.Token से पार्सर, केवल अंश भाग या एक्सपोनेंट वाले अक्षर को पारदर्शी करता है, इसलिए यह "6" को पार्स करने में असफल रहा।

हालांकि

,

*Expr> parse expr "" "variable" 
Left (line 1, column 9): 
unexpected end of input 
expecting "(" 

जब कॉल एक पहचानकर्ता पार्स करने के बाद विफल रहता है, इनपुट का वह हिस्सा सेवन किया जाता है, इसलिए अध्यक्ष की कोशिश की नहीं है, और कुल मिलाकर पार्स विफल रहता है। आप ए expr की पसंद सूची में try call बना सकते हैं, ताकि कॉल इनपुट के बिना विफल हो जाए, या बी) expr में उपयोग करने के लिए एक पार्सर कॉलऑरिडेंट लिखें, उदा।

callOrIdent = do 
    name <- identifier 
    liftM (FuncCall name) (parens $ commaSep expr) <|> return (Identifier name) 

जो try से बचाता है और इस प्रकार बेहतर प्रदर्शन कर सकता है।

+0

मैं 'पहचानकर्ता 'के लिए' Text.Parsec. टोकन' के लेक्सर फ़ंक्शंस का उपयोग करता हूं। किसी कारण से, मुझे आपके द्वारा दिए गए कोड के लिए पूरी तरह से अलग पार्सिंग परिणाम मिलते हैं। – Lanbo

+0

@ स्कैन आह, 'टोकन' का 'फ्लोट' पार्सर पूर्णांक अक्षर का विश्लेषण नहीं करता है, आपको 'a (6.0)' या इसी तरह लिखना होगा। लेकिन इसके अलावा, यह ऊपर, कम या ज्यादा की तरह व्यवहार करता है। –

+0

... अब मुझे गूंगा लगता है। धन्यवाद! (मैं अभी भी उन पूर्ण उदाहरणों की कामना करता हूं) – Lanbo

1

मैंने रोमन अंकों के साथ पारसी के साथ विश्लेषण करने के उदाहरणों की एक श्रृंखला लिखी। यह बहुत बुनियादी है, लेकिन आप या अन्य नए चेहरे इसे उपयोगी पाते हो सकता है:

https://github.com/russell91/roman

-2

पुस्तक Write Yourself a Scheme in 48 Hours एक उत्कृष्ट है, गहराई सिंहावलोकन और Parsec की कार्यक्षमता का ट्यूटोरियल में। यह आपको गहराई से उदाहरणों के साथ सब कुछ के माध्यम से चलता है, और अंत में आप एक पारसी दुभाषिया में योजना का एक बहुत ही महत्वपूर्ण हिस्सा लागू कर चुके हैं।

+2

ओपी ने स्पष्ट रूप से कहा कि यह उदाहरण पर्याप्त नहीं है। – is7s

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