用于控制流的Scala IF-ELSEIF-ELSE简单解析器组合器

用于控制流的Scala IF-ELSEIF-ELSE简单解析器组合器,scala,parser-combinators,Scala,Parser Combinators,我正在编写一个解析器组合器来解析简单的控制流语句 然后执行一些代码。语言的结构大致如下—— val resultId = 200 val s = s"""(IF $resultId == 100 GOTO NODE-1-->NODE-2) (ELSE IF $resultId > 100 GOTO NODE-1-->NODE-3) (ELSE GOTO NODE-1-->NODE-4)""".stripMargin private val result= new

我正在编写一个解析器组合器来解析简单的控制流语句 然后执行一些代码。语言的结构大致如下——

val resultId = 200
  val s = s"""(IF $resultId == 100 GOTO NODE-1-->NODE-2) (ELSE IF $resultId > 100 GOTO NODE-1-->NODE-3) (ELSE GOTO NODE-1-->NODE-4)""".stripMargin
  private val result= new ConditionalParserCombinator().run(s)
例如,在上面的场景中,我应该得到GOTO NODE-1-->NODE-3,而不是在计算else表达式后得到false,combinator代码概述如下:

final class ConditionalParserCombinator extends JavaTokenParsers with ParserCombinatorLike {
    def IF = "IF"
    def ELSE = "ELSE"
    def ELSEIF = ELSE ~ IF
    def NULL = "NULL"
    def GOTO = "GOTO"
    def node_id = wholeNumber | floatingPointNumber | stringLiteral
    def NODE = "NODE" ~ "-" ~ node_id ^^ (e ⇒ NodeExpression(e._2))
    def EDGE = NODE ~ "-->" ~ NODE ^^ (e ⇒ EdgeExpression(e._1._1, e._2))
    def lhs = ident | wholeNumber | floatingPointNumber | stringLiteral
    def rhs = ident | wholeNumber | floatingPointNumber | stringLiteral | NULL
    def operator = "==" | "*" | "/" | "||" | "&&" | ">" | "<" | ">=" | "<="
    def block = GOTO ~ EDGE
    def expression_block = lhs ~ operator ~ rhs ~ block ^^ {
      case lhs ~ operator ~ rhs ~ block ⇒ ExpressionBlock(lhs, rhs, operator, block._2)
    }
    def ifExpression = IF ~ expression_block ^^ (e ⇒ e._2.operator match {
      case "==" ⇒ if (e._2.lhs == e._2.rhs) Block(e._2.block) else false
      case ">" ⇒ if (e._2.lhs > e._2.rhs) Block(e._2.block) else false
      case "<" ⇒ if (e._2.lhs < e._2.rhs) Block(e._2.block) else false
      case _ ⇒ false
    })
    def elseIFExpression = ELSEIF ~ expression_block ^^ (e ⇒ e._2.operator match {
      case "==" ⇒ if (e._2.lhs == e._2.rhs) Block(e._2.block) else false
      case ">" ⇒ if (e._2.lhs > e._2.rhs) {
        println("matched elseif")
        Block(e._2.block)
      } else false
      case "<" ⇒ if (e._2.lhs < e._2.rhs) Block(e._2.block) else false
      case _ ⇒ false
    })
    def elseExpression = ELSE ~ block ^^ (e ⇒ Block(e._2._2))
    override def grammar = "(" ~> log(ifExpression)("ifexpression") <~ ")" ~!
      "(" ~> log(elseIFExpression)("elseifexpression") <~ ")" ~!
      "(" ~> log(elseExpression)("elseexpression") <~ ")"
  }
final类ConditionalParserCombinator使用ParserCombinatorLike扩展了JavaTokenParser{
def IF=“IF”
def ELSE=“ELSE”
def ELSEIF=ELSE~IF
def NULL=“NULL”
def GOTO=“GOTO”
def node_id=wholeNumber | floatingPointNumber | stringLiteral
def NODE=“NODE”~“-”NODE_id^^(e⇒ 节点表达式(e._2))
def EDGE=NODE~“-->”~NODE^^(e⇒ 边表达式(e._1._1,e._2))
def lhs=ident | wholeNumber | floatingPointNumber | stringLiteral
def rhs=ident | wholeNumber | floatingPointNumber | stringLiteral | NULL
def运算符=“=”|“*”|“/”|“|”|“|”&&“|”>“|”=”|“⇒ 如果(e._2.lhs>e._2.rhs)块(e._2.Block)否则为假
案例“”⇒ 如果(东2.lhs>东2.rhs){
println(“匹配的elseif”)
区块(e._2.区块)
}否则错误

case“我认为将表达式解析为您可以理解的类型(这意味着我为它定义了自定义的产品/案例类)然后对其求值更为简洁-这是两件不同的事情。事后看来,我不确定为什么我会将两者混淆在一起。下面是可行的逻辑-

def IF = "IF"
def ELSE = "ELSE"
def ELSEIF = ELSE ~ IF
def NULL = "NULL"
def GOTO = "GOTO"
def dataType: Parser[DataType] = "[" ~ "Integer" ~ "]" ^^ { e ⇒ DataType("", "Integer") }
def node_id = wholeNumber | floatingPointNumber | stringLiteral
def NODE = "NODE" ~ "-" ~ node_id ^^ (e ⇒ ParseableNode(e._2, DataType({}, "Unit")))
def EDGE = NODE ~ "-->" ~ NODE ^^ (e ⇒ EdgeExpression(e._1._1, e._2))
def lhs = ident | wholeNumber | floatingPointNumber | stringLiteral
def rhs = ident | wholeNumber | floatingPointNumber | stringLiteral | NULL
def operator = "==" | "*" | "/" | "||" | "&&" | ">" | "<" | ">=" | "<="
def block = GOTO ~ EDGE
def expression_block(expType: ConditionalKind) = dataType ~ lhs ~ operator ~ rhs ~ block ^^ {
  case dataType ~ lhs ~ operator ~ rhs ~ block ⇒ ExpressionBlock(ParseableNode(lhs, dataType), ParseableNode(rhs, dataType), operator, block._2, expType)
}
def ifExpression = IF ~ expression_block(ConditionalKind("IF")) ^^ {
  case "IF" ~ expression_block ⇒ ExpressionBlock(expression_block.lhs, expression_block.rhs, expression_block.operator, expression_block.block, expression_block.conditionalKind)
}
def elseIFExpression = ELSEIF ~ expression_block(ConditionalKind("ELSEIF")) ^^ {
  case "ELSE" ~ "IF" ~ expression_block ⇒ ExpressionBlock(expression_block.lhs, expression_block.rhs, expression_block.operator, expression_block.block, expression_block.conditionalKind)
}
def elseExpression = ELSE ~ block ^^ { case "ELSE" ~ block ⇒ Block(block._2) }
override def grammar = log(ifExpression)("ifexpression") ~ log(elseIFExpression)("elseifexpression") ~ log(elseExpression)("elseexpression") ^^ {
  case ifExpression ~ elseIFExpression ~ elseExpression ⇒
    ConditionalExpressions(List(ifExpression, elseIFExpression), elseExpression)
}
它可以做得更好,例如语法似乎违反了DRY,在每个If上嵌入数据类型,但我认为人们可以从中派生出一些东西

编辑-也请注意-这个toInt东西有点难看,需要更好的设计,一旦我这样做了,我可能会发布一个更新。我需要修改所有语法,现在一切都正常了-欢迎建议/改进,仍在学习

object BasicSelectorExpressionEvaluator extends EvaluatorLike {

override def eval(parseable: Parseable) = parseable match {
  case ConditionalExpressions(ifElseIfs, otherwise) ⇒
    val mappedIfElseIfs: immutable.Seq[Block] = ifElseIfs.map { e ⇒
      println(s"e ==>$e")
      e.operator match {
        case "==" ⇒ if (e.lhs == e.rhs) {
          println("mached ==")
          Block(e.block)
        } else Block.Unit
        case "<" ⇒ if (e.lhs.value.toInt < e.rhs.value.toInt) {
          println("matched <")
          Block(e.block)
        } else Block.Unit
        case ">" ⇒ if (e.lhs.value.toInt > e.rhs.value.toInt) {
          println("matched >")
          Block(e.block)
        } else Block.Unit
        case "<=" ⇒ if (e.lhs.value.toInt <= e.rhs.value.toInt) {
          println("mached <=")
          Block(e.block)
        } else Block.Unit
        case ">=" ⇒ if (e.lhs.value.toInt >= e.rhs.value.toInt) {
          println("mached >=")
          Block(e.block)
        } else Block.Unit
      }
    }
    val filteredMappedIFElseIfs = mappedIfElseIfs.filterNot(e ⇒ e.equals(Block.Unit))
    println(s"filteredMappedIFElseIfs == $filteredMappedIFElseIfs")
    if (filteredMappedIFElseIfs.nonEmpty) PResult(filteredMappedIFElseIfs.head.block) else PResult(otherwise.block)
}
val s = s""" IF [Integer] $resultId == 100 GOTO NODE-1-->NODE-2 ELSE IF [Integer] $resultId > 100 GOTO NODE-1-->NODE-3 ELSE GOTO NODE-1-->NODE-4""".stripMargin