class Lexer(ch : CharStream) {
val EOL = '\n'
val keywords = Map("while" -> WHILE,
"if" -> IF,
"println" -> PRINTLN,
"readln" -> READLN)
var current : Token = EOF
private def skippedComment : Boolean = {
if (ch.current == '/') {
ch.next
if (ch.current == '/') {
ch.next
while ((ch.current != EOL) && !ch.eof) ch.next
true
} else {
current = DIV
false
}
} else {
false
}
}
private def skipSpaces = {
while (((ch.current <= ' ') || skippedComment) && !ch.eof)
ch.next
}
private def isLetter : Boolean =
('A' <= ch.current && ch.current <= 'Z') ||
('a' <= ch.current && ch.current <= 'z') ||
('_' == ch.current)
private def isDigit : Boolean = ('0' <= ch.current) & (ch.current <= '9')
private def getIdent = {
var s = new StringBuffer()
while ((isLetter || isDigit) && !ch.eof) {
s.append(ch.current)
ch.next
}
val str = s.toString
if (keywords.isDefinedAt(str)) {
current = keywords(str)
} else {
current = ID(str);
}
}
private def getInt = {
var k = 0;
while (isDigit && !ch.eof) {
val digit = ch.current.asInstanceOf[Int] - '0'.asInstanceOf[Int];
k = k * 10 + digit
ch.next
}
current = IntConst(k)
}
def next : Unit = {
if (ch.eof) {current = EOF; return}
current = null
skipSpaces
if (current != null) return
if (ch.eof) {current = EOF; return}
if (isLetter) {getIdent; return}
if (isDigit) {getInt; return}
ch.current match {
case '(' => {current = OPAREN; ch.next; return}
case ')' => {current = CPAREN; ch.next; return}
case '{' => {current = OBRACE; ch.next; return}
case '}' => {current = CBRACE; ch.next; return}
case ';' => {current = SEMICOL; ch.next; return}
case '+' => {current = PLUS; ch.next; return}
case '-' => {current = MINUS; ch.next; return}
case '/' => {current = DIV; ch.next; return}
case '*' => {current = MUL; ch.next; return}
case '=' => {
ch.next
if (ch.current=='=') {ch.next; current = CompareEQ; return}
else {current = AssignEQ; return}
}
case '<' => {
ch.next
if (ch.current=='=') {ch.next; current = LEQ; return}
else {current = LESS; return}
}
case _ => {
current = new Unknown(ch.current);
ch.next
}
}
}
next // initialize lexer to first token
}