2012-11-20 27 views
6

क्या स्केल के पार्सर संयोजकों का उपयोग करने के लिए एक सुविधाजनक तरीका है जहां इंडेंटेशन महत्वपूर्ण है? (उदाहरण के लिए अजगर)स्कैला पार्सर संयोजकों का उपयोग करके इंडेंटेशन आधारित भाषा का विश्लेषण करना

+0

'ओवरराइड वैल स्किप व्हाइटसाइट = झूठी' – senia

उत्तर

5

मान लेते हैं कि हम एक बहुत ही सरल भाषा जहां यह एक वैध कार्यक्रम

block 
    inside 
    the 
    block 

है और हम एक String के रूप में ब्लॉक के अंदर प्रत्येक पंक्ति के साथ एक List[String] में इस पार्स करने के लिए चाहते हैं।

हम पहले एक ऐसी विधि को परिभाषित करते हैं जो न्यूनतम इंडेंटेशन स्तर लेता है और उस इंडेंटेशन स्तर के साथ एक रेखा के लिए एक पार्सर देता है।

def line(minIndent:Int):Parser[String] = 
    repN(minIndent + 1,"\\s".r) ~ ".*".r ^^ {case s ~ r => s.mkString + r} 

फिर हम लाइनों के बीच एक उपयुक्त विभाजक के साथ लाइन पार्सर को दोहराते हुए एक न्यूनतम खरोज स्तर के साथ एक ब्लॉक परिभाषित करते हैं।

def lines(minIndent:Int):Parser[List[String]] = 
    rep1sep(line(minIndent), "[\n\r]|(\n\r)".r) 

अब हम इस तरह हमारी छोटी सी भाषा के लिए एक पार्सर परिभाषित कर सकते हैं:

val block:Parser[List[String]] = 
    (("\\s*".r <~ "block\\n".r) ^^ { _.size }) >> lines 

यह पहली बार वर्तमान खरोज स्तर निर्धारित करता है और उसके बाद से गुजरता है कि लाइनों पार्सर के लिए कम से कम के रूप में। के परीक्षण करते हैं:

val s = 
"""block 
    inside 
    the 
    block 
outside 
the 
block""" 

println(block(new CharSequenceReader(s))) 

और हम संकलित करने के लिए मिलता है

[4.10] parsed: List( inside,  the,  block) 

इस सब के लिए, आप इन आयात

import scala.util.parsing.combinator.RegexParsers 
import scala.util.parsing.input.CharSequenceReader 

और तुम एक वस्तु है कि फैली में सब कुछ डाल करने के लिए की जरूरत की जरूरत है RegexParsers जैसे

object MyParsers extends RegexParsers { 
    override def skipWhitespace = false 
    .... 
1

जो मुझे पता है, उससे, स्कैला पार्सर संयोजकों को बॉक्स के बाहर इस तरह की चीज़ के लिए समर्थन नहीं है। आप निश्चित रूप से एक सार्थक तरीके से सफेद स्थान को पार्स करके कर सकते हैं, लेकिन आपको कुछ समस्याएं आती हैं क्योंकि आपको इंडेंटेशन स्टैक का ट्रैक रखने के लिए कुछ प्रकार की राज्य मशीन की आवश्यकता होती है।

मैं प्रीप्रोकैसिंग चरण करने की अनुशंसा करता हूं। इस पाठ के लिए

object Preprocessor { 

    val BlockStartToken = "{" 
    val BlockEndToken = "}" 

    val TabSize = 4 //how many spaces does a tab take 

    def preProcess(text: String): String = { 
     val lines = text.split('\n').toList.filterNot(_.forall(isWhiteChar)) 
     val processedLines = BlockStartToken :: insertTokens(lines, List(0)) 
     processedLines.mkString("\n") 
    } 

    def insertTokens(lines: List[String], stack: List[Int]): List[String] = lines match { 
     case List() => List.fill(stack.length) { BlockEndToken } //closing all opened blocks 
     case line :: rest => { 
      (computeIndentation(line), stack) match { 
       case (indentation, top :: stackRest) if indentation > top => { 
        BlockStartToken :: line :: insertTokens(rest, indentation :: stack) 
       } 
       case (indentation, top :: stackRest) if indentation == top => 
        line :: insertTokens(rest, stack) 
       case (indentation, top :: stackRest) if indentation < top => { 
        BlockEndToken :: insertTokens(lines, stackRest) 
       } 
       case _ => throw new IllegalStateException("Invalid algorithm") 
      } 
     } 
    } 


    private def computeIndentation(line: String): Int = { 
     val whiteSpace = line takeWhile isWhiteChar 
     (whiteSpace map { 
      case ' ' => 1 
      case '\t' => TabSize 
     }).sum 
    } 

    private def isWhiteChar(ch: Char) = ch == ' ' || ch == '\t' 
} 

निष्पादन देता है::

val text = 
    """ 
     |line1 
     |line2 
     | line3 
     | line4 
     | line5 
     |  line6 
     |  line7 
     | line8 
     | line9 
     |line10 
     | line11 
     | line12 
     | line13 
    """.stripMargin 
println(Preprocessor.preProcess(text)) 

... निम्न परिणाम

{ 
line1 
line2 
{ 
    line3 
    line4 
    line5 
{ 
     line6 
     line7 
} 
} 
{ 
    line8 
    line9 
} 
line10 
{ 
    line11 
    line12 
    line13 
} 
} 

और समापन आप कर सकते हैं यह एक छोटा सा पूर्वप्रक्रमक जो दांतेदार ब्लॉक अलग करने के लिए मार्कर कहते है एक सरल फैशन में पार्सिंग करने के लिए संयोजक लाइब्रेरी का उपयोग करें।

आशा है कि यह

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

  • कोई संबंधित समस्या नहीं^_^