From patchwork Sat Aug 17 23:48:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 1148808 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-507186-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=golang.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="NjYV8tUu"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=golang-org.20150623.gappssmtp.com header.i=@golang-org.20150623.gappssmtp.com header.b="tDwzuPpU"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 469xjv2cPpz9sBF for ; Sun, 18 Aug 2019 09:49:21 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=EXSs5yDhMHacmFvFw5xE33TcQMW0DajHPZhlLyVCXtWd3W UKWTMCAmffMfzRWmQeS3JuvTQ2pEg+4ALIBCOhd8L2y7E+0aQt8CBLW8QrTUAtUN lrYFA3fJ/361DJZNBkzZqYCSuyzdi6JKAjmIqEhVqeJ39bIbUObcx/OLklQSQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=DAuqS4qhLEL9RVl5sMQLiwcZuX8=; b=NjYV8tUuLcGQa5iOzgA6 5epUgnDjy7DNjnFE8HYAt/llDNnnX3Z9FMQ26R8wH2HeH/hZ9/oVvSFNbVPLZJTq cKT7KsDf0Sa3IWB8L+RzDhlG4E+DTZV97d6juaFBY8ZWNyyYXLnHHXsMvIqkUVih jfrv6W2jvqh8MnuYPKxJiso= Received: (qmail 103650 invoked by alias); 17 Aug 2019 23:48:45 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 103393 invoked by uid 89); 17 Aug 2019 23:48:26 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-10.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=1.13, treating, BASE, exponent X-HELO: mail-lf1-f52.google.com Received: from mail-lf1-f52.google.com (HELO mail-lf1-f52.google.com) (209.85.167.52) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 17 Aug 2019 23:48:24 +0000 Received: by mail-lf1-f52.google.com with SMTP id s19so6465659lfb.9 for ; Sat, 17 Aug 2019 16:48:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=golang-org.20150623.gappssmtp.com; s=20150623; h=mime-version:from:date:message-id:subject:to; bh=yJvOgBg62Vs/y3RlSoP8swOm0VnChsK8B4aoMCDS/mw=; b=tDwzuPpU2GyUxZieuJgUk7gWj7J0RpAUb/2M5MwoBtmV7bwXGDHflmz0SZ72fraCS1 HW6hH+D7KvsQj72h29X1GlZ4w2Sa4C8bt3Dvf45gldIniKTYmleMBUKTjbAFwo0g8AGQ KE2bsfzANjz0QhpyO8a28UwR0CsvYCF8JPed/O2BeBvvjWw+BU3OUP7B+3bfAXW7aQ7z dRrZ1NnvF4k2FnW3eL21AuXfWl6oefZqa3J0iBE5wFMHsmRZTyohYJi5fPLxNSL/lVo2 +jZgHlJG9JX/J+uYgpRLt0R3u/tPb3c++xDu4ZHX19x53J2ofc82Fhtv2EE5xFmQaMYc C7gA== MIME-Version: 1.0 From: Ian Lance Taylor Date: Sat, 17 Aug 2019 16:48:05 -0700 Message-ID: Subject: Go patch committed: Support new numeric literal syntax To: gcc-patches , gofrontend-dev This Go frontend patch adds support for new numeric literal syntax that was added to the Go 1.13 release (https://tip.golang.org/doc/go1.13#language). This supports 0b and 0o prefixes, and hex floats. This was tested against test/literal2.go in the gc repo. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 274613) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -4b47cadf938caadf563f8d0bb3f7111d06f61752 +85857977230437f2b3dcbeea009efbb8b2789039 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/lex.cc =================================================================== --- gcc/go/gofrontend/lex.cc (revision 274169) +++ gcc/go/gofrontend/lex.cc (working copy) @@ -986,6 +986,26 @@ Lex::is_hex_digit(char c) || (c >= 'a' && c <= 'f')); } +// Return whether C is a valid digit in BASE. + +bool +Lex::is_base_digit(int base, char c) +{ + switch (base) + { + case 2: + return c == '0' || c == '1'; + case 8: + return c >= '0' && c <= '7'; + case 10: + return c >= '0' && c <= '9'; + case 16: + return Lex::is_hex_digit(c); + default: + go_unreachable(); + } +} + // not a hex value #define NHV 100 @@ -1032,13 +1052,24 @@ Lex::hex_val(char c) return hex_value_lookup_table[static_cast(c)]; } -// Return whether an exponent could start at P. +// Return whether an exponent could start at P, in base BASE. bool -Lex::could_be_exponent(const char* p, const char* pend) +Lex::could_be_exponent(int base, const char* p, const char* pend) { - if (*p != 'e' && *p != 'E') - return false; + switch (base) + { + case 10: + if (*p != 'e' && *p != 'E') + return false; + break; + case 16: + if (*p != 'p' && *p != 'P') + return false; + break; + default: + go_unreachable(); + } ++p; if (p >= pend) return false; @@ -1062,87 +1093,160 @@ Lex::gather_number() Location location = this->location(); - bool neg = false; - if (*p == '+') - ++p; - else if (*p == '-') - { - ++p; - neg = true; - } - - const char* pnum = p; + int base = 10; + std::string num; if (*p == '0') { - int base; - if ((p[1] == 'x' || p[1] == 'X') - && Lex::is_hex_digit(p[2])) + int basecheck; + int off; + if (p[1] == 'x' || p[1] == 'X') { base = 16; - p += 2; - pnum = p; - while (p < pend) - { - if (!Lex::is_hex_digit(*p)) - break; - ++p; - } + basecheck = 16; + off = 2; + } + else if (p[1] == 'o' || p[1] == 'O') + { + base = 8; + basecheck = 8; + off = 2; + } + else if (p[1] == 'b' || p[1] == 'B') + { + base = 2; + basecheck = 2; + off = 2; } else { + // Old style octal literal. May also be the start of a + // floating-point number (e.g., 09.2, 09e2) or an imaginary + // literal (e.g., 09i), so we have to accept decimal digits. base = 8; - pnum = p; - while (p < pend) - { - if (*p < '0' || *p > '9') - break; - ++p; - } + basecheck = 10; + off = 0; + } + + p += off; + if (*p == '_' && Lex::is_base_digit(basecheck, p[1])) + ++p; + + while (Lex::is_base_digit(basecheck, *p)) + { + num.push_back(*p); + ++p; + if (*p == '_' && Lex::is_base_digit(basecheck, p[1])) + ++p; + } + + // We must see at least one valid digit, except for a case like + // 0x.0p1. + if (num.length() == 0 && (base != 16 || *p != '.')) + { + go_error_at(this->location(), "invalid numeric literal"); + this->lineoff_ = p - this->linebuf_; + mpz_t val; + mpz_init_set_ui(val, 0); + Token ret = Token::make_integer_token(val, location); + mpz_clear(val); + return ret; + } + + bool is_float = false; + // A number that looks like an old-style octal literal might + // actually be the beginning of a floating-point or imaginary + // literal, in which case the value is decimal digits. Handle + // that case below by treating the leading '0' as decimal. + if (off == 0 + && (*p == '.' || *p == 'i' || Lex::could_be_exponent(10, p, pend))) + { + is_float = true; + base = 10; } + else if (base == 16 + && (*p == '.' || Lex::could_be_exponent(16, p, pend))) + is_float = true; - // A partial token that looks like an octal literal might actually be the - // beginning of a floating-point or imaginary literal. - if (base == 16 || (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend))) + if (!is_float) { - std::string s(pnum, p - pnum); mpz_t val; - int r = mpz_init_set_str(val, s.c_str(), base); + int r = mpz_init_set_str(val, num.c_str(), base); if (r != 0) { - if (base == 8) - go_error_at(this->location(), "invalid octal literal"); - else - go_error_at(this->location(), "invalid hex literal"); + const char *errword; + switch (base) + { + case 2: + errword = "binary"; + break; + case 8: + errword = "octal"; + break; + case 16: + errword = "hex"; + break; + default: + go_unreachable(); + } + go_error_at(this->location(), "invalid %s literal", errword); } - if (neg) - mpz_neg(val, val); + bool is_imaginary = *p == 'i'; + if (is_imaginary) + ++p; this->lineoff_ = p - this->linebuf_; - Token ret = Token::make_integer_token(val, location); - mpz_clear(val); - return ret; + + if (*p == 'e' || *p == 'E' || *p == 'p' || *p == 'P') + { + go_error_at(location, + "invalid prefix for floating constant"); + this->skip_exponent(); + } + + if (!is_imaginary) + { + Token ret = Token::make_integer_token(val, location); + mpz_clear(val); + return ret; + } + else + { + mpfr_t ival; + mpfr_init_set_z(ival, val, GMP_RNDN); + mpz_clear(val); + Token ret = Token::make_imaginary_token(ival, location); + mpfr_clear(ival); + return ret; + } } } while (p < pend) { - if (*p < '0' || *p > '9') + if (*p == '_' && p[1] >= '0' && p[1] <= '9') + ++p; + else if (*p < '0' || *p > '9') break; + num.push_back(*p); ++p; } - if (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend)) + if (*p != '.' && *p != 'i' && !Lex::could_be_exponent(base, p, pend)) { - std::string s(pnum, p - pnum); mpz_t val; - int r = mpz_init_set_str(val, s.c_str(), 10); + int r = mpz_init_set_str(val, num.c_str(), 10); go_assert(r == 0); - if (neg) - mpz_neg(val, val); - this->lineoff_ = p - this->linebuf_; + + if (*p == 'e' || *p == 'E' || *p == 'p' || *p == 'P') + { + go_error_at(location, + "invalid prefix for floating constant"); + this->skip_exponent(); + } + Token ret = Token::make_integer_token(val, location); mpz_clear(val); return ret; @@ -1152,48 +1256,76 @@ Lex::gather_number() { bool dot = *p == '.'; + num.push_back(*p); ++p; if (!dot) { if (*p == '+' || *p == '-') - ++p; + { + num.push_back(*p); + ++p; + } } + bool first = true; while (p < pend) { - if (*p < '0' || *p > '9') + if (!first && *p == '_' && Lex::is_base_digit(base, p[1])) + ++p; + else if (!Lex::is_base_digit(base, *p)) break; + num.push_back(*p); ++p; + first = false; } - if (dot && Lex::could_be_exponent(p, pend)) + if (dot && Lex::could_be_exponent(base, p, pend)) { + num.push_back(*p); ++p; if (*p == '+' || *p == '-') - ++p; + { + num.push_back(*p); + ++p; + } + first = true; while (p < pend) { - if (*p < '0' || *p > '9') + if (!first && *p == '_' && p[1] >= '0' && p[1] <= '9') + ++p; + else if (*p < '0' || *p > '9') break; + num.push_back(*p); ++p; + first = false; } } + else if (dot && base == 16) + { + go_error_at(this->location(), + "invalid hex floating-point literal with no exponent"); + num.append("p0"); + } } - std::string s(pnum, p - pnum); mpfr_t val; - int r = mpfr_init_set_str(val, s.c_str(), 10, GMP_RNDN); + int r = mpfr_init_set_str(val, num.c_str(), base, GMP_RNDN); go_assert(r == 0); - if (neg) - mpfr_neg(val, val, GMP_RNDN); - bool is_imaginary = *p == 'i'; if (is_imaginary) ++p; this->lineoff_ = p - this->linebuf_; + + if (*p == 'e' || *p == 'E' || *p == 'p' || *p == 'P') + { + go_error_at(location, + "invalid prefix for floating constant"); + this->skip_exponent(); + } + if (is_imaginary) { Token ret = Token::make_imaginary_token(val, location); @@ -1208,6 +1340,27 @@ Lex::gather_number() } } +// Skip an exponent after reporting an error. + +void +Lex::skip_exponent() +{ + const char* p = this->linebuf_ + this->lineoff_; + const char* pend = this->linebuf_ + this->linesize_; + if (*p != 'e' && *p != 'E' && *p != 'p' && *p != 'P') + return; + ++p; + if (*p == '+' || *p == '-') + ++p; + while (p < pend) + { + if ((*p < '0' || *p > '9') && *p != '_') + break; + ++p; + } + this->lineoff_ = p - this->linebuf_; +} + // Advance one character, possibly escaped. Return the pointer beyond // the character. Set *VALUE to the character. Set *IS_CHARACTER if // this is a character (e.g., 'a' or '\u1234') rather than a byte Index: gcc/go/gofrontend/lex.h =================================================================== --- gcc/go/gofrontend/lex.h (revision 274169) +++ gcc/go/gofrontend/lex.h (working copy) @@ -462,6 +462,9 @@ class Lex static bool is_hex_digit(char); + static bool + is_base_digit(int base, char); + static unsigned char octal_value(char c) { return c - '0'; } @@ -482,11 +485,14 @@ class Lex gather_identifier(); static bool - could_be_exponent(const char*, const char*); + could_be_exponent(int base, const char*, const char*); Token gather_number(); + void + skip_exponent(); + Token gather_character();