2014-02-24 51 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