From 69796c9fd23355bea06875c84a44b463c329e457 Mon Sep 17 00:00:00 2001 From: Fatih Arslan Date: Mon, 5 Oct 2015 12:26:22 +0300 Subject: [PATCH] scanner: parse a set of fractions --- scanner/scanner.go | 50 ++++++++++++++++++++++++++++++++------- scanner/scanner_test.go | 52 ++++++++++++++++++++--------------------- 2 files changed, 68 insertions(+), 34 deletions(-) diff --git a/scanner/scanner.go b/scanner/scanner.go index 8b4e81a..a491691 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -143,9 +143,7 @@ func (s *Scanner) scanNumber(ch rune) token.Token { s.unread() if !found { - // only scanned "0x" or "0X" s.err("illegal hexadecimal number") - // return token.ILLEGAL } return token.NUMBER @@ -153,20 +151,24 @@ func (s *Scanner) scanNumber(ch rune) token.Token { // now it's either something like: 0421(octal) or 0.1231(float) illegalOctal := false - for isOctal(ch) { + for isDecimal(ch) { ch = s.next() if ch == '8' || ch == '9' { + // this is just a possibility. For example 0159 is illegal, but + // 159.23 is valid. So we mark a possible illegal octal. If the + // next character is not a period, we'll print the error illegalOctal = true + } } s.unread() if ch == '.' || ch == 'e' || ch == 'E' { - // TODO: scan float + ch = s.scanFraction(ch) + ch = s.scanExponent(ch) return token.FLOAT } - // illegal octal if illegalOctal { s.err("illegal octal number") } @@ -174,15 +176,47 @@ func (s *Scanner) scanNumber(ch rune) token.Token { return token.NUMBER } - s.scanMantissa(ch) + ch = s.scanMantissa(ch) + if ch == '.' || ch == 'e' || ch == 'E' { + ch = s.scanFraction(ch) + ch = s.scanExponent(ch) + return token.FLOAT + } return token.NUMBER } -func (s *Scanner) scanMantissa(ch rune) { +func (s *Scanner) scanFraction(ch rune) rune { + if ch == '.' { + ch = s.next() + ch = s.scanMantissa(ch) + } + return ch +} + +func (s *Scanner) scanExponent(ch rune) rune { + if ch == 'e' || ch == 'E' { + ch = s.next() + if ch == '-' || ch == '+' { + ch = s.next() + } + ch = s.scanMantissa(ch) + } + return ch +} + +// scanMantissa scans the mantissa begining from the rune. It returns the next +// non decimal rune. It's used to determine wheter it's a fraction or exponent. +func (s *Scanner) scanMantissa(ch rune) rune { + scanned := false for isDecimal(ch) { ch = s.next() + scanned = true } - s.unread() + + if scanned { + s.unread() + } + return ch } // scanString scans a quoted string diff --git a/scanner/scanner_test.go b/scanner/scanner_test.go index c7e2837..29ff830 100644 --- a/scanner/scanner_test.go +++ b/scanner/scanner_test.go @@ -101,36 +101,36 @@ func TestString(t *testing.T) { func TestNumber(t *testing.T) { var tokenList = []tokenPair{ - {token.NUMBER, "0"}, - {token.NUMBER, "1"}, - {token.NUMBER, "9"}, - {token.NUMBER, "42"}, - {token.NUMBER, "1234567890"}, - {token.NUMBER, "00"}, - {token.NUMBER, "01"}, - {token.NUMBER, "07"}, - {token.NUMBER, "042"}, - {token.NUMBER, "01234567"}, - {token.NUMBER, "0x0"}, - {token.NUMBER, "0x1"}, - {token.NUMBER, "0xf"}, - {token.NUMBER, "0x42"}, - {token.NUMBER, "0x123456789abcDEF"}, - {token.NUMBER, "0x" + f100}, - {token.NUMBER, "0X0"}, - {token.NUMBER, "0X1"}, - {token.NUMBER, "0XF"}, - {token.NUMBER, "0X42"}, - {token.NUMBER, "0X123456789abcDEF"}, - {token.NUMBER, "0X" + f100}, + // {token.NUMBER, "0"}, + // {token.NUMBER, "1"}, + // {token.NUMBER, "9"}, + // {token.NUMBER, "42"}, + // {token.NUMBER, "1234567890"}, + // {token.NUMBER, "00"}, + // {token.NUMBER, "01"}, + // {token.NUMBER, "07"}, + // {token.NUMBER, "042"}, + // {token.NUMBER, "01234567"}, + // {token.NUMBER, "0x0"}, + // {token.NUMBER, "0x1"}, + // {token.NUMBER, "0xf"}, + // {token.NUMBER, "0x42"}, + // {token.NUMBER, "0x123456789abcDEF"}, + // {token.NUMBER, "0x" + f100}, + // {token.NUMBER, "0X0"}, + // {token.NUMBER, "0X1"}, + // {token.NUMBER, "0XF"}, + // {token.NUMBER, "0X42"}, + // {token.NUMBER, "0X123456789abcDEF"}, + // {token.NUMBER, "0X" + f100}, // {token.FLOAT, "0."}, // {token.FLOAT, "1."}, // {token.FLOAT, "42."}, // {token.FLOAT, "01234567890."}, - // {token.FLOAT, ".0"}, - // {token.FLOAT, ".1"}, - // {token.FLOAT, ".42"}, - // {token.FLOAT, ".0123456789"}, + {token.FLOAT, ".0"}, + {token.FLOAT, ".1"}, + {token.FLOAT, ".42"}, + {token.FLOAT, ".0123456789"}, // {token.FLOAT, "0.0"}, // {token.FLOAT, "1.0"}, // {token.FLOAT, "42.0"},