diff --git a/lib/Translation/ForthToMLIR/ForthToMLIR.cpp b/lib/Translation/ForthToMLIR/ForthToMLIR.cpp index aa3b4cb..bea61c8 100644 --- a/lib/Translation/ForthToMLIR/ForthToMLIR.cpp +++ b/lib/Translation/ForthToMLIR/ForthToMLIR.cpp @@ -133,12 +133,39 @@ bool ForthLexer::isNumber(const std::string &str) const { return true; } +/// Float grammar: [+-]? (D+ '.' D* | '.' D+ | D+) ([eE] [+-]? D+)?, where a +/// bare D+ needs the exponent. Spelled out rather than using strtod, which +/// also accepts hex, nan and inf. bool ForthLexer::isFloat(const std::string &str) const { - if (str.empty()) + size_t i = 0; + size_t n = str.size(); + auto skipDigits = [&]() { + size_t start = i; + while (i < n && std::isdigit(static_cast(str[i]))) + ++i; + return i - start; + }; + + if (i < n && (str[i] == '+' || str[i] == '-')) + ++i; + size_t mantissaDigits = skipDigits(); + bool hasDot = i < n && str[i] == '.'; + if (hasDot) { + ++i; + mantissaDigits += skipDigits(); + } + if (mantissaDigits == 0) return false; - double value; - return llvm::to_float(str, value); + bool hasExponent = i < n && (str[i] == 'e' || str[i] == 'E'); + if (hasExponent) { + ++i; + if (i < n && (str[i] == '+' || str[i] == '-')) + ++i; + if (skipDigits() == 0) + return false; + } + return i == n && (hasDot || hasExponent); } Token ForthLexer::nextToken() { diff --git a/test/Translation/Forth/float-literal-strtod-spellings.forth b/test/Translation/Forth/float-literal-strtod-spellings.forth new file mode 100644 index 0000000..9b7e4be --- /dev/null +++ b/test/Translation/Forth/float-literal-strtod-spellings.forth @@ -0,0 +1,19 @@ +\ RUN: %warpforth-translate --forth-to-mlir %s | %FileCheck %s + +\ Hex, nan and inf spellings are ordinary words, not float literals. +\ CHECK-NOT: f64 +\ CHECK: func.func private @NAN( +\ CHECK: func.func private @INF( +\ CHECK: func.func private @INFINITY( +\ CHECK: func.func private @_0X1P3( +\ CHECK: func.func @main() +\ CHECK: call @NAN( +\ CHECK: call @INF( +\ CHECK: call @INFINITY( +\ CHECK: call @_0X1P3( +\! kernel main +: nan 7 ; +: inf 8 ; +: infinity 9 ; +: 0x1p3 10 ; +nan inf infinity 0x1p3 diff --git a/test/Translation/Forth/float-literals.forth b/test/Translation/Forth/float-literals.forth index 31d8f16..26b4c8b 100644 --- a/test/Translation/Forth/float-literals.forth +++ b/test/Translation/Forth/float-literals.forth @@ -5,5 +5,11 @@ \ CHECK-NEXT: forth.constant %{{.*}}(-2.000000e+00 : f64) \ CHECK-NEXT: forth.constant %{{.*}}(1.000000e-05 : f64) \ CHECK-NEXT: forth.constant %{{.*}}(1.000000e+03 : f64) +\ CHECK-NEXT: forth.constant %{{.*}}(1.000000e+03 : f64) +\ CHECK-NEXT: forth.constant %{{.*}}(5.000000e-01 : f64) +\ CHECK-NEXT: forth.constant %{{.*}}(-5.000000e-01 : f64) +\ CHECK-NEXT: forth.constant %{{.*}}(5.000000e+00 : f64) +\ CHECK-NEXT: forth.constant %{{.*}}(1.500000e+00 : f64) +\ CHECK-NEXT: forth.constant %{{.*}}(2.500000e+02 : f64) \! kernel main -3.14 -2.0 1.0e-5 1e3 +3.14 -2.0 1.0e-5 1e3 1E3 .5 -.5 5. +1.5 2.5e+2 diff --git a/test/Translation/Forth/hex-literal-error.forth b/test/Translation/Forth/hex-literal-error.forth new file mode 100644 index 0000000..94ffbc2 --- /dev/null +++ b/test/Translation/Forth/hex-literal-error.forth @@ -0,0 +1,5 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: {{.*}}hex-literal-error.forth:5:1: error: unknown word: 0X10 +\! kernel k +\! param a i64[1] +0x10 a !