2014-02-24 49 views
1

我正在使用Scala解析器組合器編寫DSL,並且具有可讀取單個文件並解析它的工作版本。但是,我想將我的輸入分成幾個文件,其中一些文件是「標準」的,可以與任何頂層文件一起使用。我想是這樣的:Scala:使用Scala的組合器解析多個文件

進口 「a.dsl」
進口 「b.dsl」 文件
//休息使用{A,B}

它不是」重要的是讀取文件的順序或者在被引用之前必須「定義」某些東西,所以首先解析頂層文件然後將所有導入的關閉解析爲單個模型就足夠了。然後,我將爲我自己的目的後處理生成的模型。

我的問題是,有沒有一個合理的方法來完成這個?如果有必要,我可以遍歷閉包,將每個文件解析爲一個單獨的模型,並手動「合併」所得到的模型,但這種感覺很笨重,對我來說似乎很難看。

順便說一句,我使用的擴展名爲StandardTokenParsers,如果有關係。

回答

2

我認爲唯一的方法是直接打開和解析導入的文件。從那裏你可以爲模塊創建一個子表達式樹。例如,如果您已經使用^^和/或^^^來返回自己的表達式,那麼您可能不需要手動合併樹,例如,您應該能夠在樹中的正確位置簡單發出相關的表達式類型,例如:

import scala.util.parsing.combinator.syntactical.StandardTokenParsers 
import scala.io.Source 

object Example { 

    sealed trait Expr 

    case class Imports(modules: List[Module]) extends Expr 
    case class Module(modulePath: String, root: Option[Expr]) extends Expr 
    case class BracedExpr(x: String, y: String) extends Expr 
    case class Main(imports: Imports, braced: BracedExpr) extends Expr 


    class BlahTest extends StandardTokenParsers { 

    def importExpr: Parser[Module] = "import" ~> "\"" ~> stringLit <~ "\"" ^^ { 
     case modulePath => 

     //you could use something other than `expr` below if you 
     //wanted to limit the expressions available in modules 
     //e.g. you could stop one module importing another. 
     phrase(expr)(new lexical.Scanner(Source.fromFile(modulePath).mkString)) match { 
      case Success(result, _) => 
      Module(modulePath, Some(result)) 

      case failure : NoSuccess => 
      //TODO log or act on failure 
      Module(modulePath, None) 
     } 
    } 

    def prologExprs = rep(importExpr) ^^ { 
     case modules => 
     Imports(modules) 
    } 

    def bracedExpr = "{" ~> stringLit ~ "," ~ stringLit <~ "}" ^^ { 
     case x ~ "," ~ y => 
     BracedExpr(x, y) 
    } 

    def bodyExprs = bracedExpr 

    def expr = prologExprs ~ bodyExprs ^^ { 
     case prolog ~ body => 
     Main(prolog, body) 
    } 

    } 

} 

你可以簡單地添加eval到你的表達特點,實現每個EVAL必要的子類,然後有客人遞歸下降的AST。以這種方式,您不需要手動將表達式樹合併在一起。

+0

啊,謝謝你。我想我可以爲我的案子做這件事。順便說一句,我不認爲你需要importExpr中的轉義引號,是嗎? stringLit是否已經引用了報價? – melston

+0

確實,您不需要importExpr中的轉義引號。 'stringLit'的確包含並放棄了這些。當我寫代碼的時候,道歉很晚。因此,您的'importExpr'可以從下面開始: 'def importExpr:Parser [Module] =「import」〜> stringLit ^^' – adamretter