/ / Scala: analizar múltiples archivos usando los combinadores de Scala - scala, parser-combinators

Scala: análisis de múltiples archivos utilizando los combinadores de Scala: scala, analizadores de analizadores

Estoy escribiendo un DSL usando los combinadores de analizador de Scalay tiene una versión funcional que puede leer un solo archivo y analizarlo. Sin embargo, me gustaría dividir mi entrada en varios archivos donde algunos archivos son "estándar" y se pueden usar con cualquier archivo de nivel superior. Lo que me gustaría es algo como:

importar "a.dsl"
importar "b.dsl"
// resto del archivo usando {a, b}

No es importante el orden en que se leen los archivos.en o que algo está necesariamente "definido" antes de referirse, por lo que analizar el archivo de nivel superior primero y luego analizar el cierre de todas las importaciones en un solo modelo es suficiente. Luego, postprocesaré el modelo resultante para mis propios propósitos.

La pregunta que tengo es, ¿hay una manera razonable?de lograr esto? Si fuera necesario, podría recorrer el cierre, analizar cada archivo en un modelo separado y "fusionar" manualmente los modelos resultantes, pero esto me parece torpe y me parece feo.

Por cierto, estoy usando una extensión de StandardTokenParsers, si eso importa.

Respuestas

2 para la respuesta № 1

Creo que el único enfoque sería abrir yanalizar el archivo indicado por la importación directamente. Desde allí puede crear un árbol de sub-expresión para el módulo. Es posible que no necesite combinar manualmente los árboles al analizar, por ejemplo, si ya está utilizando ^^ y / o ^^^ para devolver sus propias Expresiones, entonces debería poder emitir simplemente un tipo de expresión relevante en el lugar correcto dentro del árbol, por ejemplo:

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)
}

}

}

Usted podría simplemente agregar un eval a su rasgo de Expresión, implemente cada eval comonecesario en las subclases y luego hacer que un visitante descienda recursivamente su AST. De esta manera, no sería necesario fusionar manualmente los árboles de expresión.