2014-02-24 3 views
1

스칼라 파서 결합자를 사용하여 DSL을 작성하고 단일 파일을 읽고 구문 분석 할 수있는 작업 버전이 있습니다. 그러나 일부 파일이 '표준'이며 모든 최상위 파일에 사용할 수있는 여러 파일로 입력 내용을 분할하고 싶습니다. 내가하고 싶은 것은 같은 :스칼라 : 스칼라의 결합자를 사용하여 여러 파일 구문 분석

수입 "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) 
    } 

    } 

} 

당신은 단순히 각각의 서브 클래스에 필요한 평가 및 다음 방문자가 재귀 AST를 내려 구현, 당신의 표현 특성에 eval을 추가 할 수 있습니다. 이 방식으로 수식 트리를 수동으로 병합 할 필요가 없습니다.

+0

아, 고마워. 제 생각에는이 일을 할 수 있다고 생각합니다. BTW, 나는 당신이 importExpr에서 이스케이프 된 따옴표가 필요하다고 생각하지 않습니까? stringLit은 이미 따옴표를 고려하지 않습니까? – melston

+0

예, 실제로는 importExpr에 이스케이프 된 따옴표가 필요하지 않습니다. 'stringLit'은 실제로 그것을 포함하고 버립니다. 사과를하면 코드를 작성했을 때 꽤 늦었습니다. 따라서'importExpr'은 아래와 같이 시작될 수 있습니다 : 'def importExpr : 파서 ​​[Module] = "import"~> stringLit ^^' – adamretter