4
votes

I'm trying to write a parser in Scala for SML with Tokens. It almost works the way I want it to work, except for the fact that this currently parses

let fun f x = r and fun g y in r end;

instead of

let fun f x = r and g y in r end;

How do I change my code so that it recognizes that it doesn't need a FunToken for the second function?

def parseDef:Def = {
  currentToken match {
  case ValToken => {
    eat(ValToken);

    val nme:String = currentToken match {
      case IdToken(x) => {advance; x}
      case _ => error("Expected a name after VAL.")
    }

    eat(EqualToken);      
    VAL(nme,parseExp)
    }

  case FunToken => {

    eat(FunToken);

    val fnme:String = currentToken match {
      case IdToken(x) => {advance; x}
      case _ => error("Expected a name after VAL.")
    }

    val xnme:String = currentToken match {
      case IdToken(x) => {advance; x}
      case _ => error("Expected a name after VAL.")
    }

    def parseAnd:Def = currentToken match {
      case AndToken => {eat(AndToken); FUN(fnme,xnme,parseExp,parseAnd)}
      case _ => NOFUN
    }


    FUN(fnme,xnme,parseExp,parseAnd)
    }
    case _ => error("Expected VAL or FUN.");
  }
}
2

2 Answers

1
votes

Just implement the right grammar. Instead of

def ::= "val" id "=" exp | fun
fun ::= "fun" id id "=" exp ["and" fun]

SML's grammar actually is

def ::= "val" id "=" exp | "fun" fun
fun ::= id id "=" exp ["and" fun]

Btw, I think there are other problems with your parsing of fun. AFAICS, you are not parsing any "=" in the fun case. Moreover, after an "and", you are not even parsing any identifiers, just the function body.

0
votes

You could inject the FunToken back into your input stream with an "uneat" function. This is not the most elegant solution, but it's the one that requires the least modification of your current code.

def parseAnd:Def = currentToken match {
    case AndToken => { eat(AndToken); 
                       uneat(FunToken);
                       FUN(fnme,xnme,parseExp,parseAnd) }
  case _ => NOFUN
}