Scala: использование StandardTokenParser для разбора шестнадцатеричных чисел - PullRequest
6 голосов
/ 13 августа 2010

Я использую комбинаторный парсер Scala, расширяя scala.util.parsing.combinator.syntactical.StandardTokenParser.Этот класс предоставляет следующие методы

def ident : Parser[String] для анализа идентификаторов и

def numericLit : Parser[String] для анализа числа (я полагаю, десятичное)

Я использую scala.util.parsing.combinator.lexical.Scanners из scala.util.parsing.combinator.lexical.StdLexical для лексинга.

Мое требование - разобрать шестнадцатеричное число (без префикса 0x), которое может иметь любую длину.В основном грамматика, такая как: ([0-9]|[a-f])+

Я пытался интегрировать парсер Regex, но там есть проблемы с типами.Другие способы расширить определение правил лексера и правил грамматики приводят к тому, что токен не найден!

Ответы [ 2 ]

5 голосов
/ 23 августа 2010

Как я и думал, проблему можно решить, расширив поведение Lexer, а не Parser. Стандартный лексер принимает только десятичные цифры, поэтому я создал новый лексер:

class MyLexer extends StdLexical {
  override type Elem = Char
  override def digit = ( super.digit | hexDigit )
  lazy val hexDigits = Set[Char]() ++ "0123456789abcdefABCDEF".toArray
  lazy val hexDigit = elem("hex digit", hexDigits.contains(_))
}

И мой парсер (который должен быть StandardTokenParser) может быть расширен следующим образом:

object ParseAST extends StandardTokenParsers{

  override val lexical:MyLexer = new MyLexer()
  lexical.delimiters += ( "(" , ")" , "," , "@")
  ...
 }

Построение «числа» из цифр обеспечивается классом StdLexical:

class StdLexical {
...

def token: Parser[Token] = 
    ...
| digit~rep(digit)^^{case first ~ rest => NumericLit(first :: rest mkString "")}
}

Поскольку StdLexical выдает только проанализированный номер в виде строки, для меня это не проблема, так как меня не интересует также числовое значение.

3 голосов
/ 17 августа 2010

Вы можете использовать RegexParsers с действием, связанным с данным токеном.

import scala.util.parsing.combinator._

object HexParser extends RegexParsers {
  val hexNum: Parser[Int] = """[0-9a-f]+""".r ^^ 
           { case s:String => Integer.parseInt(s,16) } 

  def seq: Parser[Any] = repsep(hexNum, ",")

}

Это определит парсер, который читает разделенный запятыми шестнадцатеричный номер без предварительного 0x. И он на самом деле вернет Int.

val result = HexParser.parse(HexParser.seq, "1, 2, f, 10, 1a2b34d")
scala> println(result)
[1.21] parsed: List(1, 2, 15, 16, 27439949)

Не существует способа различения десятичных числовых обозначений. Также я использую Integer.parseInt, это ограничено размером вашего Int. Чтобы получить любую длину, вам может потребоваться создать собственный анализатор и использовать BigInteger или массивы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...