Commit ed1a5e5d authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: cleanup number lexing

Change-Id: Ib0dd458d4ab1c58a2baf36491e288ac32e2ff99e
Reviewed-on: https://go-review.googlesource.com/19962Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 36f25a7e
...@@ -1355,34 +1355,27 @@ var keywords = map[string]int32{ ...@@ -1355,34 +1355,27 @@ var keywords = map[string]int32{
} }
func (l *lexer) number(c rune) { func (l *lexer) number(c rune) {
// TODO(gri) this can be done nicely with fewer or even without labels
var str string var str string
cp := &lexbuf cp := &lexbuf
cp.Reset() cp.Reset()
// parse mantissa before decimal point or exponent
isInt := false
malformedOctal := false
if c != '.' { if c != '.' {
if c != '0' { if c != '0' {
// decimal or float
for isDigit(c) { for isDigit(c) {
cp.WriteByte(byte(c)) cp.WriteByte(byte(c))
c = l.getr() c = l.getr()
} }
if c == '.' {
goto casedot
}
if c == 'e' || c == 'E' || c == 'p' || c == 'P' {
goto caseep
}
if c == 'i' {
goto casei
}
goto ncu
}
} else {
// c == 0 // c == 0
cp.WriteByte('0') cp.WriteByte('0')
c = l.getr() c = l.getr()
if c == 'x' || c == 'X' { if c == 'x' || c == 'X' {
isInt = true // must be int
cp.WriteByte(byte(c)) cp.WriteByte(byte(c))
c = l.getr() c = l.getr()
for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
...@@ -1392,72 +1385,51 @@ func (l *lexer) number(c rune) { ...@@ -1392,72 +1385,51 @@ func (l *lexer) number(c rune) {
if lexbuf.Len() == 2 { if lexbuf.Len() == 2 {
Yyerror("malformed hex constant") Yyerror("malformed hex constant")
} }
if c == 'p' { } else {
goto caseep // decimal 0, octal, or float
}
goto ncu
}
if c == 'p' { // 0p begins floating point zero
goto caseep
}
has8or9 := false
for isDigit(c) { for isDigit(c) {
if c > '7' { if c > '7' {
has8or9 = true malformedOctal = true
} }
cp.WriteByte(byte(c)) cp.WriteByte(byte(c))
c = l.getr() c = l.getr()
} }
if c == '.' {
goto casedot
} }
if c == 'e' || c == 'E' {
goto caseep
} }
if c == 'i' {
goto casei
}
if has8or9 {
Yyerror("malformed octal constant")
}
goto ncu
} }
casedot: // unless we have a hex number, parse fractional part or exponent, if any
if !isInt {
isInt = true // assume int unless proven otherwise
// fraction // fraction
// c == '.' if c == '.' {
isInt = false
cp.WriteByte('.') cp.WriteByte('.')
c = l.getr() c = l.getr()
for isDigit(c) { for isDigit(c) {
cp.WriteByte(byte(c)) cp.WriteByte(byte(c))
c = l.getr() c = l.getr()
} }
if c == 'i' { // Falling through to exponent parsing here permits invalid
goto casei // floating-point numbers with fractional mantissa and base-2
} // (p or P) exponent. We don't care because base-2 exponents
if c != 'e' && c != 'E' { // can only show up in machine-generated textual export data
goto caseout // which will use correct formatting.
} }
// base-2-exponents (p or P) don't appear in numbers
// with fractions - ok to not test for 'p' or 'P'
// above
caseep:
// exponent // exponent
if importpkg == nil && (c == 'p' || c == 'P') { // base-2 exponent (p or P) is only allowed in export data (see #9036)
// <mantissa>p<base-2-exponent> is allowed in .a/.o imports, // TODO(gri) Once we switch to binary import data, importpkg will
// but not in .go sources. See #9036. // always be nil in this function. Simplify the code accordingly.
Yyerror("malformed floating point constant") if c == 'e' || c == 'E' || importpkg != nil && (c == 'p' || c == 'P') {
} isInt = false
cp.WriteByte(byte(c)) cp.WriteByte(byte(c))
c = l.getr() c = l.getr()
if c == '+' || c == '-' { if c == '+' || c == '-' {
cp.WriteByte(byte(c)) cp.WriteByte(byte(c))
c = l.getr() c = l.getr()
} }
if !isDigit(c) { if !isDigit(c) {
Yyerror("malformed floating point constant exponent") Yyerror("malformed floating point constant exponent")
} }
...@@ -1465,60 +1437,61 @@ caseep: ...@@ -1465,60 +1437,61 @@ caseep:
cp.WriteByte(byte(c)) cp.WriteByte(byte(c))
c = l.getr() c = l.getr()
} }
if c != 'i' {
goto caseout
} }
casei:
// imaginary constant // imaginary constant
cp = nil if c == 'i' {
str = lexbuf.String() str = lexbuf.String()
l.val.U = new(Mpcplx) x := new(Mpcplx)
Mpmovecflt(&l.val.U.(*Mpcplx).Real, 0.0) Mpmovecflt(&x.Real, 0.0)
mpatoflt(&l.val.U.(*Mpcplx).Imag, str) mpatoflt(&x.Imag, str)
if l.val.U.(*Mpcplx).Imag.Val.IsInf() { if x.Imag.Val.IsInf() {
Yyerror("overflow in imaginary constant") Yyerror("overflow in imaginary constant")
Mpmovecflt(&l.val.U.(*Mpcplx).Imag, 0.0) Mpmovecflt(&x.Imag, 0.0)
} }
l.val.U = x
if Debug['x'] != 0 { if Debug['x'] != 0 {
fmt.Printf("lex: imaginary literal\n") fmt.Printf("lex: imaginary literal\n")
} }
goto done goto done
}
}
caseout:
cp = nil
l.ungetr(c) l.ungetr(c)
if isInt {
if malformedOctal {
Yyerror("malformed octal constant")
}
str = lexbuf.String() str = lexbuf.String()
l.val.U = newMpflt() x := new(Mpint)
mpatoflt(l.val.U.(*Mpflt), str) mpatofix(x, str)
if l.val.U.(*Mpflt).Val.IsInf() { if x.Ovf {
Yyerror("overflow in float constant") Yyerror("overflow in constant")
Mpmovecflt(l.val.U.(*Mpflt), 0.0) Mpmovecfix(x, 0)
} }
l.val.U = x
if Debug['x'] != 0 { if Debug['x'] != 0 {
fmt.Printf("lex: floating literal\n") fmt.Printf("lex: integer literal\n")
} }
goto done
ncu: } else { // float
cp = nil
l.ungetr(c)
str = lexbuf.String() str = lexbuf.String()
l.val.U = new(Mpint) x := newMpflt()
mpatofix(l.val.U.(*Mpint), str) mpatoflt(x, str)
if l.val.U.(*Mpint).Ovf { if x.Val.IsInf() {
Yyerror("overflow in constant") Yyerror("overflow in float constant")
Mpmovecfix(l.val.U.(*Mpint), 0) Mpmovecflt(x, 0.0)
} }
l.val.U = x
if Debug['x'] != 0 { if Debug['x'] != 0 {
fmt.Printf("lex: integer literal\n") fmt.Printf("lex: floating literal\n")
}
} }
done: done:
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Expects to see error messages on "p" exponents. // Expects to see error messages on 'p' exponents.
package main package main
...@@ -14,11 +14,19 @@ const ( ...@@ -14,11 +14,19 @@ const (
x1 = 1.1 // float x1 = 1.1 // float
x2 = 1e10 // float x2 = 1e10 // float
x3 = 0x1e10 // integer (e is a hex digit) x3 = 0x1e10 // integer (e is a hex digit)
x4 = 0x1p10 // ERROR "malformed floating point constant"
x5 = 1p10 // ERROR "malformed floating point constant"
x6 = 0p0 // ERROR "malformed floating point constant"
) )
// 'p' exponents are invalid - the 'p' is not considered
// part of a floating-point number, but introduces a new
// (unexpected) name.
//
// Error recovery is not ideal and we use a new declaration
// each time for the parser to recover.
const x4 = 0x1p10 // ERROR "unexpected p10"
const x5 = 1p10 // ERROR "unexpected p10"
const x6 = 0p0 // ERROR "unexpected p0"
func main() { func main() {
fmt.Printf("%g %T\n", x1, x1) fmt.Printf("%g %T\n", x1, x1)
fmt.Printf("%g %T\n", x2, x2) fmt.Printf("%g %T\n", x2, x2)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment