parser1.scala
author Christian Urban <christian dot urban at kcl dot ac dot uk>
Wed, 21 Nov 2012 02:34:37 +0000
changeset 68 a09ecb1e7384
parent 62 5988e44ea048
permissions -rw-r--r--
tuned
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
62
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     1
:load matcher.scala
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     2
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     3
// some regular expressions
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     4
val DIGIT = RANGE("0123456789".toList)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     5
val NONZERODIGIT = RANGE("123456789".toList)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     6
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     7
val NUMBER = ALT(SEQ(NONZERODIGIT, STAR(DIGIT)), "0")
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     8
val LPAREN = CHAR('(')
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     9
val RPAREN = CHAR(')')
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    10
val WHITESPACE = PLUS(RANGE(" \n".toList))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    11
val OPS = RANGE("+-*".toList)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    12
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    13
// for classifying the strings that have been recognised
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    14
abstract class Token
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
case object T_WHITESPACE extends Token
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    16
case object T_NUM extends Token
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    17
case class T_OP(s: String) extends Token
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    18
case object T_LPAREN extends Token
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    19
case object T_RPAREN extends Token
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
case class T_NT(s: String, rhs: List[Token]) extends Token
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    21
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    22
def tokenizer(rs: List[Rule[Token]], s: String) : List[Token] = 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    23
  tokenize(rs, s.toList).filterNot(_ match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    24
    case T_WHITESPACE => true
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    25
    case _ => false
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    26
  })
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    27
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    28
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    29
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    30
// lexing rules for arithmetic expressions
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    31
val lexing_rules: List[Rule[Token]]= 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    32
  List((NUMBER, (s) => T_NUM),
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    33
       (WHITESPACE, (s) => T_WHITESPACE),
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    34
       (LPAREN, (s) => T_LPAREN),
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    35
       (RPAREN, (s) => T_RPAREN),
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    36
       (OPS, (s) => T_OP(s.mkString)))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    37
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    38
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    39
type Grammar = List[(String, List[Token])]
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    40
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    41
// grammar for arithmetic expressions
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    42
val grammar = 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    43
  List ("E" -> List(T_NUM),
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    44
        "E" -> List(T_NT("E", Nil), T_OP("+"), T_NT("E", Nil)),
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    45
        "E" -> List(T_NT("E", Nil), T_OP("-"), T_NT("E", Nil)),
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    46
        "E" -> List(T_NT("E", Nil), T_OP("*"), T_NT("E", Nil)),    
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    47
        "E" -> List(T_LPAREN, T_NT("E", Nil), T_RPAREN))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    48
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    49
def startsWith[A](ts1: List[A], ts2: List[A]) : Boolean = (ts1, ts2) match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    50
  case (_, Nil) => true
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    51
  case (T_NT(e, _)::ts1,T_NT(f, _)::ts2) => (e == f) && startsWith(ts1, ts2)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    52
  case (t1::ts1, t2::ts2) => (t1 == t2) && startsWith(ts1, ts2)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    53
  case _ => false
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    54
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    55
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    56
def chop[A](ts1: List[A], prefix: List[A], ts2: List[A]) : Option[(List[A], List[A])] = 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    57
  ts1 match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    58
    case Nil => None
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    59
    case t::ts => 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    60
      if (startsWith(ts1, prefix)) Some(ts2.reverse, ts1.drop(prefix.length))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    61
      else chop(ts, prefix, t::ts2)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    62
  }
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    63
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    64
// examples
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    65
chop(List(1,2,3,4,5,6,7,8,9), List(4,5), Nil)  
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    66
chop(List(1,2,3,4,5,6,7,8,9), List(3,5), Nil)  
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    67
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    68
def replace[A](ts: List[A], out: List[A], in: List [A]) = 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    69
  chop(ts, out, Nil) match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    70
    case None => None
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    71
    case Some((before, after)) => Some(before ::: in ::: after)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    72
  }  
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    73
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    74
def parse1(g: Grammar, ts: List[Token]) : Boolean = ts match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    75
  case List(T_NT("E", tree)) => { println(tree); true }
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    76
  case _ => {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    77
    val tss = for ((lhs, rhs) <- g) yield replace(ts, rhs, List(T_NT(lhs, rhs)))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    78
    tss.flatten.exists(parse1(g, _))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    79
  }
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    80
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    81
 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    82
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    83
println() ; parse1(grammar, tokenizer(lexing_rules, "2 + 3 * 4 + 1"))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    84
println() ; parse1(grammar, tokenizer(lexing_rules, "(2 + 3) * (4 + 1)"))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    85
println() ; parse1(grammar, tokenizer(lexing_rules, "(2 + 3) * 4 (4 + 1)"))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    86
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    87
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    88