2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
2016-03-11 13:39:20 -05:00
|
|
|
"bufio"
|
2016-04-05 14:20:04 -07:00
|
|
|
"bytes"
|
2015-02-13 14:40:36 -05:00
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"unicode"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
EOF = -1
|
2016-03-11 14:28:16 -08:00
|
|
|
BOM = 0xFEFF
|
2015-02-13 14:40:36 -05:00
|
|
|
)
|
|
|
|
|
|
2016-04-05 14:20:04 -07:00
|
|
|
// lexlineno is the line number _after_ the most recently read rune.
|
|
|
|
|
// In particular, it's advanced (or rewound) as newlines are read (or unread).
|
|
|
|
|
var lexlineno int32
|
|
|
|
|
|
|
|
|
|
// lineno is the line number at the start of the most recently lexed token.
|
|
|
|
|
var lineno int32
|
|
|
|
|
|
|
|
|
|
var lexbuf bytes.Buffer
|
|
|
|
|
var strbuf bytes.Buffer
|
|
|
|
|
var litbuf string // LLITERAL value for use in syntax error messages
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func isSpace(c rune) bool {
|
2015-09-24 15:41:05 +02:00
|
|
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func isLetter(c rune) bool {
|
|
|
|
|
return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_'
|
2015-09-24 15:41:05 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func isDigit(c rune) bool {
|
2015-09-24 15:41:05 +02:00
|
|
|
return '0' <= c && c <= '9'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func plan9quote(s string) string {
|
|
|
|
|
if s == "" {
|
|
|
|
|
return "''"
|
|
|
|
|
}
|
|
|
|
|
for _, c := range s {
|
|
|
|
|
if c <= ' ' || c == '\'' {
|
|
|
|
|
return "'" + strings.Replace(s, "'", "''", -1) + "'"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 17:49:31 -08:00
|
|
|
type Pragma uint16
|
2016-02-26 13:32:28 -08:00
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
Nointerface Pragma = 1 << iota
|
|
|
|
|
Noescape // func parameters don't escape
|
|
|
|
|
Norace // func must not have race detector annotations
|
|
|
|
|
Nosplit // func should not execute on separate stack
|
|
|
|
|
Noinline // func should not be inlined
|
|
|
|
|
Systemstack // func must run on system stack
|
|
|
|
|
Nowritebarrier // emit compiler error instead of write barrier
|
|
|
|
|
Nowritebarrierrec // error on write barrier in this or recursive callees
|
2016-02-27 17:49:31 -08:00
|
|
|
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
|
2016-02-26 13:32:28 -08:00
|
|
|
)
|
|
|
|
|
|
2016-02-20 11:06:35 -08:00
|
|
|
type lexer struct {
|
2016-02-22 11:53:20 -08:00
|
|
|
// source
|
2016-03-11 13:55:53 -08:00
|
|
|
bin *bufio.Reader
|
|
|
|
|
prevlineno int32 // line no. of most recently read character
|
2016-02-22 11:53:20 -08:00
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
nlsemi bool // if set, '\n' and EOF translate to ';'
|
2016-02-20 11:06:35 -08:00
|
|
|
|
2016-02-26 13:32:28 -08:00
|
|
|
// pragma flags
|
|
|
|
|
// accumulated by lexer; reset by parser
|
|
|
|
|
pragma Pragma
|
|
|
|
|
|
2016-02-20 11:06:35 -08:00
|
|
|
// current token
|
|
|
|
|
tok int32
|
2016-02-25 17:27:10 -08:00
|
|
|
sym_ *Sym // valid if tok == LNAME
|
|
|
|
|
val Val // valid if tok == LLITERAL
|
2016-03-01 14:47:26 -08:00
|
|
|
op Op // valid if tok == LOPER, LASOP, or LINCOP, or prec > 0
|
2016-02-25 17:27:10 -08:00
|
|
|
prec OpPrec // operator precedence; 0 if not a binary operator
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
type OpPrec int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// Precedences of binary operators (must be > 0).
|
|
|
|
|
PCOMM OpPrec = 1 + iota
|
|
|
|
|
POROR
|
|
|
|
|
PANDAND
|
|
|
|
|
PCMP
|
|
|
|
|
PADD
|
|
|
|
|
PMUL
|
|
|
|
|
)
|
|
|
|
|
|
2015-11-23 14:11:15 -08:00
|
|
|
const (
|
2016-02-24 16:17:49 -08:00
|
|
|
// The value of single-char tokens is just their character's Unicode value.
|
|
|
|
|
// They are all below utf8.RuneSelf. Shift other tokens up to avoid conflicts.
|
2016-03-01 14:47:26 -08:00
|
|
|
|
|
|
|
|
// names and literals
|
|
|
|
|
LNAME = utf8.RuneSelf + iota
|
|
|
|
|
LLITERAL
|
|
|
|
|
|
|
|
|
|
// operator-based operations
|
|
|
|
|
LOPER
|
2015-11-23 14:11:15 -08:00
|
|
|
LASOP
|
2016-03-01 14:47:26 -08:00
|
|
|
LINCOP
|
|
|
|
|
|
|
|
|
|
// miscellaneous
|
2015-11-23 14:11:15 -08:00
|
|
|
LCOLAS
|
2016-03-01 14:47:26 -08:00
|
|
|
LCOMM
|
|
|
|
|
LDDD
|
|
|
|
|
|
|
|
|
|
// keywords
|
2015-11-23 14:11:15 -08:00
|
|
|
LBREAK
|
|
|
|
|
LCASE
|
|
|
|
|
LCHAN
|
|
|
|
|
LCONST
|
|
|
|
|
LCONTINUE
|
|
|
|
|
LDEFAULT
|
|
|
|
|
LDEFER
|
|
|
|
|
LELSE
|
|
|
|
|
LFALL
|
|
|
|
|
LFOR
|
|
|
|
|
LFUNC
|
|
|
|
|
LGO
|
|
|
|
|
LGOTO
|
|
|
|
|
LIF
|
|
|
|
|
LIMPORT
|
|
|
|
|
LINTERFACE
|
|
|
|
|
LMAP
|
|
|
|
|
LPACKAGE
|
|
|
|
|
LRANGE
|
|
|
|
|
LRETURN
|
|
|
|
|
LSELECT
|
|
|
|
|
LSTRUCT
|
|
|
|
|
LSWITCH
|
|
|
|
|
LTYPE
|
|
|
|
|
LVAR
|
2016-03-01 14:47:26 -08:00
|
|
|
|
2015-11-23 14:11:15 -08:00
|
|
|
LIGNORE
|
|
|
|
|
)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-11 15:22:24 -08:00
|
|
|
var lexn = map[rune]string{
|
|
|
|
|
LNAME: "NAME",
|
|
|
|
|
LLITERAL: "LITERAL",
|
|
|
|
|
|
|
|
|
|
LOPER: "OPER",
|
|
|
|
|
LASOP: "ASOP",
|
|
|
|
|
LINCOP: "INCOP",
|
|
|
|
|
|
|
|
|
|
LCOLAS: "COLAS",
|
|
|
|
|
LCOMM: "COMM",
|
|
|
|
|
LDDD: "DDD",
|
|
|
|
|
|
|
|
|
|
LBREAK: "BREAK",
|
|
|
|
|
LCASE: "CASE",
|
|
|
|
|
LCHAN: "CHAN",
|
|
|
|
|
LCONST: "CONST",
|
|
|
|
|
LCONTINUE: "CONTINUE",
|
|
|
|
|
LDEFAULT: "DEFAULT",
|
|
|
|
|
LDEFER: "DEFER",
|
|
|
|
|
LELSE: "ELSE",
|
|
|
|
|
LFALL: "FALL",
|
|
|
|
|
LFOR: "FOR",
|
|
|
|
|
LFUNC: "FUNC",
|
|
|
|
|
LGO: "GO",
|
|
|
|
|
LGOTO: "GOTO",
|
|
|
|
|
LIF: "IF",
|
|
|
|
|
LIMPORT: "IMPORT",
|
|
|
|
|
LINTERFACE: "INTERFACE",
|
|
|
|
|
LMAP: "MAP",
|
|
|
|
|
LPACKAGE: "PACKAGE",
|
|
|
|
|
LRANGE: "RANGE",
|
|
|
|
|
LRETURN: "RETURN",
|
|
|
|
|
LSELECT: "SELECT",
|
|
|
|
|
LSTRUCT: "STRUCT",
|
|
|
|
|
LSWITCH: "SWITCH",
|
|
|
|
|
LTYPE: "TYPE",
|
|
|
|
|
LVAR: "VAR",
|
|
|
|
|
|
|
|
|
|
// LIGNORE is never escaping lexer.next
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func lexname(lex rune) string {
|
|
|
|
|
if s, ok := lexn[lex]; ok {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("LEX-%d", lex)
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
func (l *lexer) next() {
|
|
|
|
|
nlsemi := l.nlsemi
|
|
|
|
|
l.nlsemi = false
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = 0
|
2016-02-20 12:53:34 -08:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
l0:
|
2016-02-20 12:53:34 -08:00
|
|
|
// skip white space
|
2016-02-22 23:07:30 -08:00
|
|
|
c := l.getr()
|
2016-02-20 12:53:34 -08:00
|
|
|
for isSpace(c) {
|
|
|
|
|
if c == '\n' && nlsemi {
|
2015-02-23 17:34:49 -05:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: implicit semi\n")
|
|
|
|
|
}
|
cmd/compile: rationalize (lex)?lineno handling
Previously, many error messages inconsistantly used either lexlineno
and lineno. In general this works out okay because they're almost
always the same. The only exceptional case is after lexing a
multi-line raw string literal, where lineno will be the line number of
the opening quote and lexlineno is the line number of the closing
quote.
This CL makes the compiler's error message more consistent:
- Lexer error messages related to invalid byte sequences (i.e., NUL
bytes, bad UTF-8 sequences, and non-initial BOMs) are emitted at
lexlineno (i.e., the source line that contains the invalid byte
sequence).
- All other error messages (notably the parser's "syntax errors") now
use lineno. The minor change from this is that bogus input like:
package `
bogus`
will emit "syntax error: unexpected string literal, expecting name"
error at line 1, instead of line 2.
- Instead of maintaining prevlineno all the time, just record it
when/where actually needed and not already available elsewhere (which
turns out to be just one function).
- Lastly, we remove the legacy "syntax error near ..." fallback in
Yerror, now that the parser always emits more detailed syntax error
messages.
Change-Id: Iaf5f784223d0385fa3a5b09ef2b2ad447feab02f
Reviewed-on: https://go-review.googlesource.com/19925
Reviewed-by: Robert Griesemer <gri@golang.org>
2016-02-25 16:07:04 -08:00
|
|
|
// Insert implicit semicolon on previous line,
|
|
|
|
|
// before the newline character.
|
|
|
|
|
lineno = lexlineno - 1
|
2016-02-20 12:53:34 -08:00
|
|
|
l.tok = ';'
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
// start of token
|
|
|
|
|
lineno = lexlineno
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
// identifiers and keywords
|
|
|
|
|
// (for better error messages consume all chars >= utf8.RuneSelf for identifiers)
|
|
|
|
|
if isLetter(c) || c >= utf8.RuneSelf {
|
2016-02-23 22:04:20 -08:00
|
|
|
l.ident(c)
|
|
|
|
|
if l.tok == LIGNORE {
|
2016-02-22 23:07:30 -08:00
|
|
|
goto l0
|
|
|
|
|
}
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-24 16:17:49 -08:00
|
|
|
// c < utf8.RuneSelf
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
var c1 rune
|
|
|
|
|
var op Op
|
2016-02-25 17:27:10 -08:00
|
|
|
var prec OpPrec
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
switch c {
|
|
|
|
|
case EOF:
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2016-02-20 12:53:34 -08:00
|
|
|
// Treat EOF as "end of line" for the purposes
|
|
|
|
|
// of inserting a semicolon.
|
|
|
|
|
if nlsemi {
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: implicit semi\n")
|
|
|
|
|
}
|
|
|
|
|
l.tok = ';'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
l.tok = -1
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
|
|
|
l.number(c)
|
|
|
|
|
return
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
case '.':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-09-11 00:03:19 +02:00
|
|
|
if isDigit(c1) {
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2016-02-23 22:04:20 -08:00
|
|
|
l.number('.')
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '.' {
|
2016-03-11 13:39:20 -05:00
|
|
|
p, err := l.bin.Peek(1)
|
|
|
|
|
if err == nil && p[0] == '.' {
|
|
|
|
|
l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
c = LDDD
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2015-02-13 14:40:36 -05:00
|
|
|
c1 = '.'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '"':
|
2016-02-23 22:04:20 -08:00
|
|
|
l.stdString()
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '`':
|
2016-02-23 22:04:20 -08:00
|
|
|
l.rawString()
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '\'':
|
2016-02-23 22:04:20 -08:00
|
|
|
l.rune()
|
2016-02-20 12:53:34 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '/':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '*' {
|
2016-02-25 22:10:48 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
for {
|
2016-02-25 22:10:48 -08:00
|
|
|
if c == '*' {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c == '/' {
|
2016-02-25 22:10:48 -08:00
|
|
|
break
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-25 22:10:48 -08:00
|
|
|
continue
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if c == EOF {
|
|
|
|
|
Yyerror("eof in comment")
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
2016-02-25 22:10:48 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-25 22:10:48 -08:00
|
|
|
|
|
|
|
|
// A comment containing newlines acts like a newline.
|
|
|
|
|
if lexlineno > lineno && nlsemi {
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: implicit semi\n")
|
|
|
|
|
}
|
|
|
|
|
l.tok = ';'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
goto l0
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '/' {
|
2016-02-22 11:53:20 -08:00
|
|
|
c = l.getlinepragma()
|
2015-02-13 14:40:36 -05:00
|
|
|
for {
|
|
|
|
|
if c == '\n' || c == EOF {
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2015-02-13 14:40:36 -05:00
|
|
|
goto l0
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
op = ODIV
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop1
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ':':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = LCOLAS
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '*':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OMUL
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '%':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OMOD
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '+':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OADD
|
|
|
|
|
goto incop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '-':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OSUB
|
|
|
|
|
goto incop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '>':
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '>' {
|
2016-02-25 17:27:10 -08:00
|
|
|
op = ORSH
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-02-25 17:27:10 -08:00
|
|
|
l.op = OGE
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
2016-02-25 17:27:10 -08:00
|
|
|
l.op = OGT
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '<':
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '<' {
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OLSH
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '-' {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = LCOMM
|
2016-02-25 17:27:10 -08:00
|
|
|
// Not a binary operator, but parsed as one
|
|
|
|
|
// so we can give a good error message when used
|
|
|
|
|
// in an expression context.
|
|
|
|
|
l.prec = PCOMM
|
|
|
|
|
l.op = OSEND
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
|
|
|
|
if c1 == '=' {
|
|
|
|
|
l.op = OLE
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
l.op = OLT
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '=':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
|
|
|
|
l.op = OEQ
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '!':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
|
|
|
|
l.op = ONE
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '&':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '&' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PANDAND
|
|
|
|
|
l.op = OANDAND
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '^' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OANDNOT
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OAND
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop1
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '|':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '|' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = POROR
|
|
|
|
|
l.op = OOROR
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OOR
|
|
|
|
|
prec = PADD
|
|
|
|
|
goto binop1
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '^':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OXOR
|
|
|
|
|
prec = PADD
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
case '(', '[', '{', ',', ';':
|
|
|
|
|
goto lx
|
|
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
case ')', ']', '}':
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
goto lx
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
case '#', '$', '?', '@', '\\':
|
|
|
|
|
if importpkg != nil {
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
2016-02-22 23:07:30 -08:00
|
|
|
// anything else is illegal
|
|
|
|
|
Yyerror("syntax error: illegal character %#U", c)
|
|
|
|
|
goto l0
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
lx:
|
2015-11-27 16:11:05 -08:00
|
|
|
if Debug['x'] != 0 {
|
2016-02-25 17:27:10 -08:00
|
|
|
if c >= utf8.RuneSelf {
|
2016-03-02 11:30:29 -08:00
|
|
|
fmt.Printf("%v lex: TOKEN %s\n", linestr(lineno), lexname(c))
|
2015-11-27 16:11:05 -08:00
|
|
|
} else {
|
2016-03-02 11:30:29 -08:00
|
|
|
fmt.Printf("%v lex: TOKEN '%c'\n", linestr(lineno), c)
|
2015-02-23 17:34:49 -05:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
l.tok = c
|
2016-02-20 12:53:34 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
incop:
|
|
|
|
|
c1 = l.getr()
|
|
|
|
|
if c1 == c {
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
l.op = op
|
|
|
|
|
c = LINCOP
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
prec = PADD
|
|
|
|
|
goto binop1
|
|
|
|
|
|
|
|
|
|
binop:
|
|
|
|
|
c1 = l.getr()
|
|
|
|
|
binop1:
|
|
|
|
|
if c1 != '=' {
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2016-02-25 17:27:10 -08:00
|
|
|
l.op = op
|
|
|
|
|
l.prec = prec
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
l.op = op
|
2015-02-23 17:34:49 -05:00
|
|
|
if Debug['x'] != 0 {
|
2015-11-27 16:11:05 -08:00
|
|
|
fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op])
|
2015-02-23 17:34:49 -05:00
|
|
|
}
|
2016-02-20 12:53:34 -08:00
|
|
|
l.tok = LASOP
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) ident(c rune) {
|
|
|
|
|
cp := &lexbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
|
|
|
|
// accelerate common case (7bit ASCII)
|
|
|
|
|
for isLetter(c) || isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// general case
|
|
|
|
|
for {
|
|
|
|
|
if c >= utf8.RuneSelf {
|
|
|
|
|
if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || importpkg != nil && c == 0xb7 {
|
|
|
|
|
if cp.Len() == 0 && unicode.IsDigit(c) {
|
|
|
|
|
Yyerror("identifier cannot begin with digit %#U", c)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Yyerror("invalid identifier character %#U", c)
|
|
|
|
|
}
|
|
|
|
|
cp.WriteRune(c)
|
|
|
|
|
} else if isLetter(c) || isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
cp = nil
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-26 01:37:28 -08:00
|
|
|
name := lexbuf.Bytes()
|
|
|
|
|
|
|
|
|
|
if len(name) >= 2 {
|
|
|
|
|
if tok, ok := keywords[string(name)]; ok {
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: %s\n", lexname(tok))
|
|
|
|
|
}
|
|
|
|
|
switch tok {
|
|
|
|
|
case LBREAK, LCONTINUE, LFALL, LRETURN:
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
}
|
|
|
|
|
l.tok = tok
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s := LookupBytes(name)
|
2016-02-23 22:04:20 -08:00
|
|
|
if Debug['x'] != 0 {
|
2016-02-26 01:37:28 -08:00
|
|
|
fmt.Printf("lex: ident %s\n", s)
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
l.sym_ = s
|
2016-02-26 01:37:28 -08:00
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LNAME
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var keywords = map[string]int32{
|
|
|
|
|
"break": LBREAK,
|
|
|
|
|
"case": LCASE,
|
|
|
|
|
"chan": LCHAN,
|
|
|
|
|
"const": LCONST,
|
|
|
|
|
"continue": LCONTINUE,
|
|
|
|
|
"default": LDEFAULT,
|
|
|
|
|
"defer": LDEFER,
|
|
|
|
|
"else": LELSE,
|
|
|
|
|
"fallthrough": LFALL,
|
|
|
|
|
"for": LFOR,
|
|
|
|
|
"func": LFUNC,
|
|
|
|
|
"go": LGO,
|
|
|
|
|
"goto": LGOTO,
|
|
|
|
|
"if": LIF,
|
|
|
|
|
"import": LIMPORT,
|
|
|
|
|
"interface": LINTERFACE,
|
|
|
|
|
"map": LMAP,
|
|
|
|
|
"package": LPACKAGE,
|
|
|
|
|
"range": LRANGE,
|
|
|
|
|
"return": LRETURN,
|
|
|
|
|
"select": LSELECT,
|
|
|
|
|
"struct": LSTRUCT,
|
|
|
|
|
"switch": LSWITCH,
|
|
|
|
|
"type": LTYPE,
|
|
|
|
|
"var": LVAR,
|
|
|
|
|
|
|
|
|
|
// 💩
|
|
|
|
|
"notwithstanding": LIGNORE,
|
|
|
|
|
"thetruthofthematter": LIGNORE,
|
|
|
|
|
"despiteallobjections": LIGNORE,
|
|
|
|
|
"whereas": LIGNORE,
|
|
|
|
|
"insofaras": LIGNORE,
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
func (l *lexer) number(c rune) {
|
|
|
|
|
cp := &lexbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
// parse mantissa before decimal point or exponent
|
|
|
|
|
isInt := false
|
|
|
|
|
malformedOctal := false
|
2016-02-23 22:04:20 -08:00
|
|
|
if c != '.' {
|
|
|
|
|
if c != '0' {
|
2016-02-24 12:53:28 -08:00
|
|
|
// decimal or float
|
2016-02-23 22:04:20 -08:00
|
|
|
for isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// c == 0
|
|
|
|
|
cp.WriteByte('0')
|
|
|
|
|
c = l.getr()
|
|
|
|
|
if c == 'x' || c == 'X' {
|
|
|
|
|
isInt = true // must be int
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
|
|
|
|
if lexbuf.Len() == 2 {
|
|
|
|
|
Yyerror("malformed hex constant")
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// decimal 0, octal, or float
|
|
|
|
|
for isDigit(c) {
|
|
|
|
|
if c > '7' {
|
|
|
|
|
malformedOctal = true
|
|
|
|
|
}
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
// unless we have a hex number, parse fractional part or exponent, if any
|
2016-03-24 20:57:53 +11:00
|
|
|
var str string
|
2016-02-24 12:53:28 -08:00
|
|
|
if !isInt {
|
|
|
|
|
isInt = true // assume int unless proven otherwise
|
|
|
|
|
|
|
|
|
|
// fraction
|
|
|
|
|
if c == '.' {
|
|
|
|
|
isInt = false
|
|
|
|
|
cp.WriteByte('.')
|
|
|
|
|
c = l.getr()
|
|
|
|
|
for isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
|
|
|
|
// Falling through to exponent parsing here permits invalid
|
|
|
|
|
// floating-point numbers with fractional mantissa and base-2
|
|
|
|
|
// (p or P) exponent. We don't care because base-2 exponents
|
|
|
|
|
// can only show up in machine-generated textual export data
|
|
|
|
|
// which will use correct formatting.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// exponent
|
|
|
|
|
// base-2 exponent (p or P) is only allowed in export data (see #9036)
|
|
|
|
|
// TODO(gri) Once we switch to binary import data, importpkg will
|
|
|
|
|
// always be nil in this function. Simplify the code accordingly.
|
|
|
|
|
if c == 'e' || c == 'E' || importpkg != nil && (c == 'p' || c == 'P') {
|
|
|
|
|
isInt = false
|
2016-02-23 22:04:20 -08:00
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
2016-02-24 12:53:28 -08:00
|
|
|
if c == '+' || c == '-' {
|
2016-02-23 22:04:20 -08:00
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
if !isDigit(c) {
|
|
|
|
|
Yyerror("malformed floating point constant exponent")
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
for isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
// imaginary constant
|
|
|
|
|
if c == 'i' {
|
|
|
|
|
str = lexbuf.String()
|
|
|
|
|
x := new(Mpcplx)
|
2016-03-20 13:55:42 -07:00
|
|
|
x.Real.SetFloat64(0.0)
|
|
|
|
|
x.Imag.SetString(str)
|
2016-02-24 12:53:28 -08:00
|
|
|
if x.Imag.Val.IsInf() {
|
|
|
|
|
Yyerror("overflow in imaginary constant")
|
2016-03-20 13:55:42 -07:00
|
|
|
x.Imag.SetFloat64(0.0)
|
2016-02-24 12:53:28 -08:00
|
|
|
}
|
|
|
|
|
l.val.U = x
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: imaginary literal\n")
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
goto done
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2015-02-23 17:34:49 -05:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
if isInt {
|
|
|
|
|
if malformedOctal {
|
|
|
|
|
Yyerror("malformed octal constant")
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
str = lexbuf.String()
|
|
|
|
|
x := new(Mpint)
|
2016-03-20 13:55:42 -07:00
|
|
|
x.SetString(str)
|
2016-02-24 12:53:28 -08:00
|
|
|
if x.Ovf {
|
|
|
|
|
Yyerror("overflow in constant")
|
2016-03-20 13:55:42 -07:00
|
|
|
x.SetInt64(0)
|
2016-02-24 12:53:28 -08:00
|
|
|
}
|
|
|
|
|
l.val.U = x
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: integer literal\n")
|
|
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
} else { // float
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
str = lexbuf.String()
|
|
|
|
|
x := newMpflt()
|
2016-03-20 13:55:42 -07:00
|
|
|
x.SetString(str)
|
2016-02-24 12:53:28 -08:00
|
|
|
if x.Val.IsInf() {
|
|
|
|
|
Yyerror("overflow in float constant")
|
2016-03-20 13:55:42 -07:00
|
|
|
x.SetFloat64(0.0)
|
2016-02-24 12:53:28 -08:00
|
|
|
}
|
|
|
|
|
l.val.U = x
|
|
|
|
|
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: floating literal\n")
|
|
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
2015-02-24 20:54:57 +00:00
|
|
|
litbuf = "literal " + str
|
2016-02-20 12:53:34 -08:00
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) stdString() {
|
|
|
|
|
lexbuf.Reset()
|
|
|
|
|
lexbuf.WriteString(`"<string>"`)
|
|
|
|
|
|
|
|
|
|
cp := &strbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
for {
|
|
|
|
|
r, b, ok := l.onechar('"')
|
|
|
|
|
if !ok {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if r == 0 {
|
|
|
|
|
cp.WriteByte(b)
|
2016-02-23 22:04:20 -08:00
|
|
|
} else {
|
2016-02-24 11:49:31 -08:00
|
|
|
cp.WriteRune(r)
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l.val.U = internString(cp.Bytes())
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: string literal\n")
|
|
|
|
|
}
|
|
|
|
|
litbuf = "string literal"
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) rawString() {
|
|
|
|
|
lexbuf.Reset()
|
|
|
|
|
lexbuf.WriteString("`<string>`")
|
|
|
|
|
|
|
|
|
|
cp := &strbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
c := l.getr()
|
|
|
|
|
if c == '\r' {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if c == EOF {
|
|
|
|
|
Yyerror("eof in string")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if c == '`' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
cp.WriteRune(c)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
l.val.U = internString(cp.Bytes())
|
2015-02-23 17:34:49 -05:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: string literal\n")
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
litbuf = "string literal"
|
2016-02-20 12:53:34 -08:00
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
func (l *lexer) rune() {
|
2016-02-24 11:49:31 -08:00
|
|
|
r, b, ok := l.onechar('\'')
|
|
|
|
|
if !ok {
|
2016-02-23 22:04:20 -08:00
|
|
|
Yyerror("empty character literal or unescaped ' in character literal")
|
2016-02-24 11:49:31 -08:00
|
|
|
r = '\''
|
|
|
|
|
}
|
|
|
|
|
if r == 0 {
|
|
|
|
|
r = rune(b)
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
if c := l.getr(); c != '\'' {
|
2016-02-23 22:04:20 -08:00
|
|
|
Yyerror("missing '")
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x := new(Mpint)
|
|
|
|
|
l.val.U = x
|
2016-03-20 13:55:42 -07:00
|
|
|
x.SetInt64(int64(r))
|
2016-02-23 22:04:20 -08:00
|
|
|
x.Rune = true
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: codepoint literal\n")
|
|
|
|
|
}
|
|
|
|
|
litbuf = "rune literal"
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
var internedStrings = map[string]string{}
|
|
|
|
|
|
|
|
|
|
func internString(b []byte) string {
|
|
|
|
|
s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
|
2016-02-22 11:53:20 -08:00
|
|
|
if !ok {
|
|
|
|
|
s = string(b)
|
|
|
|
|
internedStrings[s] = s
|
2015-03-02 16:03:26 -05:00
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func more(pp *string) bool {
|
|
|
|
|
p := *pp
|
2016-02-22 23:07:30 -08:00
|
|
|
for p != "" && isSpace(rune(p[0])) {
|
2015-02-13 14:40:36 -05:00
|
|
|
p = p[1:]
|
|
|
|
|
}
|
|
|
|
|
*pp = p
|
|
|
|
|
return p != ""
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// read and interpret syntax that looks like
|
|
|
|
|
// //line parse.y:15
|
|
|
|
|
// as a discontinuity in sequential line numbers.
|
|
|
|
|
// the next line of input comes from parse.y:15
|
2016-02-22 23:07:30 -08:00
|
|
|
func (l *lexer) getlinepragma() rune {
|
|
|
|
|
c := l.getr()
|
2015-06-08 10:17:38 -07:00
|
|
|
if c == 'g' { // check for //go: directive
|
2015-03-02 12:35:15 -05:00
|
|
|
cp := &lexbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
cp.WriteByte('g') // already read
|
|
|
|
|
for {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-03-02 12:35:15 -05:00
|
|
|
if c == EOF || c >= utf8.RuneSelf {
|
|
|
|
|
return c
|
|
|
|
|
}
|
|
|
|
|
if c == '\n' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
}
|
|
|
|
|
cp = nil
|
|
|
|
|
|
2015-07-17 22:29:44 -07:00
|
|
|
text := strings.TrimSuffix(lexbuf.String(), "\r")
|
2015-03-08 22:41:48 -04:00
|
|
|
|
|
|
|
|
if strings.HasPrefix(text, "go:cgo_") {
|
|
|
|
|
pragcgo(text)
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-08 10:17:38 -07:00
|
|
|
verb := text
|
|
|
|
|
if i := strings.Index(text, " "); i >= 0 {
|
2015-03-02 12:35:15 -05:00
|
|
|
verb = verb[:i]
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-08 10:17:38 -07:00
|
|
|
switch verb {
|
|
|
|
|
case "go:linkname":
|
2015-09-11 00:03:19 +02:00
|
|
|
if !imported_unsafe {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
|
|
|
|
|
}
|
2015-06-08 10:17:38 -07:00
|
|
|
f := strings.Fields(text)
|
2015-03-02 12:35:15 -05:00
|
|
|
if len(f) != 3 {
|
|
|
|
|
Yyerror("usage: //go:linkname localname linkname")
|
2015-06-08 10:17:38 -07:00
|
|
|
break
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
Lookup(f[1]).Linkname = f[2]
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nointerface":
|
|
|
|
|
if obj.Fieldtrack_enabled != 0 {
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nointerface
|
2015-06-08 10:17:38 -07:00
|
|
|
}
|
|
|
|
|
case "go:noescape":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Noescape
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:norace":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Norace
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nosplit":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nosplit
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:noinline":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Noinline
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:systemstack":
|
2015-09-03 17:39:20 -04:00
|
|
|
if compiling_runtime == 0 {
|
|
|
|
|
Yyerror("//go:systemstack only allowed in runtime")
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Systemstack
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nowritebarrier":
|
2015-03-02 12:35:15 -05:00
|
|
|
if compiling_runtime == 0 {
|
|
|
|
|
Yyerror("//go:nowritebarrier only allowed in runtime")
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nowritebarrier
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nowritebarrierrec":
|
2015-11-02 16:45:07 -05:00
|
|
|
if compiling_runtime == 0 {
|
|
|
|
|
Yyerror("//go:nowritebarrierrec only allowed in runtime")
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
|
2016-02-27 17:49:31 -08:00
|
|
|
case "go:cgo_unsafe_args":
|
|
|
|
|
l.pragma |= CgoUnsafeArgs
|
2015-11-02 16:45:07 -05:00
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-06-08 10:17:38 -07:00
|
|
|
|
|
|
|
|
// check for //line directive
|
2015-02-13 14:40:36 -05:00
|
|
|
if c != 'l' {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := 1; i < 5; i++ {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
|
|
|
|
if c != rune("line "[i]) {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
cp := &lexbuf
|
2015-02-13 14:40:36 -05:00
|
|
|
cp.Reset()
|
2015-03-02 12:35:15 -05:00
|
|
|
linep := 0
|
2015-02-13 14:40:36 -05:00
|
|
|
for {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c == EOF {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if c == '\n' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if c == ' ' {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if c == ':' {
|
|
|
|
|
linep = cp.Len() + 1
|
|
|
|
|
}
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
}
|
|
|
|
|
cp = nil
|
|
|
|
|
|
|
|
|
|
if linep == 0 {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-07-17 22:29:44 -07:00
|
|
|
text := strings.TrimSuffix(lexbuf.String(), "\r")
|
2015-06-08 10:17:38 -07:00
|
|
|
n, err := strconv.Atoi(text[linep:])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return c // todo: make this an error instead? it is almost certainly a bug.
|
|
|
|
|
}
|
|
|
|
|
if n > 1e8 {
|
|
|
|
|
Yyerror("line number out of range")
|
|
|
|
|
errorexit()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n <= 0 {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-08 10:17:38 -07:00
|
|
|
linehistupdate(text[:linep-1], n)
|
2015-02-13 14:40:36 -05:00
|
|
|
return c
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getimpsym(pp *string) string {
|
|
|
|
|
more(pp) // skip spaces
|
|
|
|
|
p := *pp
|
|
|
|
|
if p == "" || p[0] == '"' {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
i := 0
|
2016-02-22 23:07:30 -08:00
|
|
|
for i < len(p) && !isSpace(rune(p[i])) && p[i] != '"' {
|
2015-02-13 14:40:36 -05:00
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
sym := p[:i]
|
|
|
|
|
*pp = p[i:]
|
|
|
|
|
return sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getquoted(pp *string) (string, bool) {
|
|
|
|
|
more(pp) // skip spaces
|
|
|
|
|
p := *pp
|
|
|
|
|
if p == "" || p[0] != '"' {
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
p = p[1:]
|
|
|
|
|
i := strings.Index(p, `"`)
|
|
|
|
|
if i < 0 {
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
*pp = p[i+1:]
|
|
|
|
|
return p[:i], true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copied nearly verbatim from the C compiler's #pragma parser.
|
|
|
|
|
// TODO: Rewrite more cleanly once the compiler is written in Go.
|
|
|
|
|
func pragcgo(text string) {
|
|
|
|
|
var q string
|
|
|
|
|
|
|
|
|
|
if i := strings.Index(text, " "); i >= 0 {
|
|
|
|
|
text, q = text[:i], text[i:]
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
verb := text[3:] // skip "go:"
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if verb == "cgo_dynamic_linker" || verb == "dynlinker" {
|
2015-09-11 00:03:19 +02:00
|
|
|
p, ok := getquoted(&q)
|
2015-02-13 14:40:36 -05:00
|
|
|
if !ok {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_dynamic_linker %v\n", plan9quote(p))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "dynexport" {
|
|
|
|
|
verb = "cgo_export_dynamic"
|
|
|
|
|
}
|
|
|
|
|
if verb == "cgo_export_static" || verb == "cgo_export_dynamic" {
|
2015-02-23 16:07:24 -05:00
|
|
|
local := getimpsym(&q)
|
|
|
|
|
var remote string
|
2015-02-13 14:40:36 -05:00
|
|
|
if local == "" {
|
|
|
|
|
goto err2
|
|
|
|
|
}
|
|
|
|
|
if !more(&q) {
|
|
|
|
|
pragcgobuf += fmt.Sprintf("%s %v\n", verb, plan9quote(local))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remote = getimpsym(&q)
|
|
|
|
|
if remote == "" {
|
|
|
|
|
goto err2
|
|
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("%s %v %v\n", verb, plan9quote(local), plan9quote(remote))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
err2:
|
|
|
|
|
Yyerror("usage: //go:%s local [remote]", verb)
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "cgo_import_dynamic" || verb == "dynimport" {
|
|
|
|
|
var ok bool
|
2015-02-23 16:07:24 -05:00
|
|
|
local := getimpsym(&q)
|
|
|
|
|
var p string
|
|
|
|
|
var remote string
|
2015-02-13 14:40:36 -05:00
|
|
|
if local == "" {
|
|
|
|
|
goto err3
|
|
|
|
|
}
|
|
|
|
|
if !more(&q) {
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v\n", plan9quote(local))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remote = getimpsym(&q)
|
|
|
|
|
if remote == "" {
|
|
|
|
|
goto err3
|
|
|
|
|
}
|
|
|
|
|
if !more(&q) {
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v\n", plan9quote(local), plan9quote(remote))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p, ok = getquoted(&q)
|
|
|
|
|
if !ok {
|
|
|
|
|
goto err3
|
|
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v %v\n", plan9quote(local), plan9quote(remote), plan9quote(p))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
err3:
|
|
|
|
|
Yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]")
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "cgo_import_static" {
|
2015-02-23 16:07:24 -05:00
|
|
|
local := getimpsym(&q)
|
2015-02-13 14:40:36 -05:00
|
|
|
if local == "" || more(&q) {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("usage: //go:cgo_import_static local")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_static %v\n", plan9quote(local))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "cgo_ldflag" {
|
2015-09-11 00:03:19 +02:00
|
|
|
p, ok := getquoted(&q)
|
2015-02-13 14:40:36 -05:00
|
|
|
if !ok {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("usage: //go:cgo_ldflag \"arg\"")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func (l *lexer) getr() rune {
|
2016-03-11 13:39:20 -05:00
|
|
|
redo:
|
2016-03-11 13:55:53 -08:00
|
|
|
l.prevlineno = lexlineno
|
2016-03-11 13:39:20 -05:00
|
|
|
r, w, err := l.bin.ReadRune()
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err != io.EOF {
|
|
|
|
|
Fatalf("io error: %v", err)
|
2016-02-22 23:07:30 -08:00
|
|
|
}
|
2016-03-11 13:39:20 -05:00
|
|
|
return -1
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-11 13:39:20 -05:00
|
|
|
switch r {
|
|
|
|
|
case 0:
|
|
|
|
|
yyerrorl(lexlineno, "illegal NUL byte")
|
|
|
|
|
case '\n':
|
|
|
|
|
if importpkg == nil {
|
2016-02-22 23:07:30 -08:00
|
|
|
lexlineno++
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-11 13:39:20 -05:00
|
|
|
case utf8.RuneError:
|
|
|
|
|
if w == 1 {
|
|
|
|
|
yyerrorl(lexlineno, "illegal UTF-8 sequence")
|
|
|
|
|
}
|
|
|
|
|
case BOM:
|
2016-03-02 11:01:25 -08:00
|
|
|
yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file")
|
2016-02-22 23:07:30 -08:00
|
|
|
goto redo
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
return r
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-11 13:55:53 -08:00
|
|
|
func (l *lexer) ungetr() {
|
2016-03-11 13:39:20 -05:00
|
|
|
l.bin.UnreadRune()
|
2016-03-11 13:55:53 -08:00
|
|
|
lexlineno = l.prevlineno
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
// onechar lexes a single character within a rune or interpreted string literal,
|
|
|
|
|
// handling escape sequences as necessary.
|
|
|
|
|
func (l *lexer) onechar(quote rune) (r rune, b byte, ok bool) {
|
2016-02-22 23:07:30 -08:00
|
|
|
c := l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
switch c {
|
|
|
|
|
case EOF:
|
|
|
|
|
Yyerror("eof in string")
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2016-02-24 11:49:31 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '\n':
|
|
|
|
|
Yyerror("newline in string")
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2016-02-24 11:49:31 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '\\':
|
|
|
|
|
break
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
case quote:
|
|
|
|
|
return
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
2016-02-24 11:49:31 -08:00
|
|
|
return c, 0, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
switch c {
|
|
|
|
|
case 'x':
|
2016-02-24 11:49:31 -08:00
|
|
|
return 0, byte(l.hexchar(2)), true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case 'u':
|
2016-02-24 11:49:31 -08:00
|
|
|
return l.unichar(4), 0, true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case 'U':
|
2016-02-24 11:49:31 -08:00
|
|
|
return l.unichar(8), 0, true
|
|
|
|
|
|
|
|
|
|
case '0', '1', '2', '3', '4', '5', '6', '7':
|
|
|
|
|
x := c - '0'
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 2; i > 0; i-- {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-03-02 12:35:15 -05:00
|
|
|
if c >= '0' && c <= '7' {
|
2016-02-24 11:49:31 -08:00
|
|
|
x = x*8 + c - '0'
|
2015-03-02 12:35:15 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Yyerror("non-octal character in escape sequence: %c", c)
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 11:53:20 -08:00
|
|
|
if x > 255 {
|
|
|
|
|
Yyerror("octal escape value > 255: %d", x)
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
return 0, byte(x), true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
|
c = '\a'
|
|
|
|
|
case 'b':
|
|
|
|
|
c = '\b'
|
|
|
|
|
case 'f':
|
|
|
|
|
c = '\f'
|
|
|
|
|
case 'n':
|
|
|
|
|
c = '\n'
|
|
|
|
|
case 'r':
|
|
|
|
|
c = '\r'
|
|
|
|
|
case 't':
|
|
|
|
|
c = '\t'
|
|
|
|
|
case 'v':
|
|
|
|
|
c = '\v'
|
|
|
|
|
case '\\':
|
|
|
|
|
c = '\\'
|
|
|
|
|
|
|
|
|
|
default:
|
2016-02-24 11:49:31 -08:00
|
|
|
if c != quote {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("unknown escape sequence: %c", c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
return c, 0, true
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
func (l *lexer) unichar(n int) rune {
|
|
|
|
|
x := l.hexchar(n)
|
|
|
|
|
if x > utf8.MaxRune || 0xd800 <= x && x < 0xe000 {
|
2016-02-22 11:53:20 -08:00
|
|
|
Yyerror("invalid Unicode code point in escape sequence: %#x", x)
|
|
|
|
|
x = utf8.RuneError
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-24 11:49:31 -08:00
|
|
|
return rune(x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) hexchar(n int) uint32 {
|
|
|
|
|
var x uint32
|
|
|
|
|
|
|
|
|
|
for ; n > 0; n-- {
|
|
|
|
|
var d uint32
|
|
|
|
|
switch c := l.getr(); {
|
|
|
|
|
case isDigit(c):
|
|
|
|
|
d = uint32(c - '0')
|
|
|
|
|
case 'a' <= c && c <= 'f':
|
|
|
|
|
d = uint32(c - 'a' + 10)
|
|
|
|
|
case 'A' <= c && c <= 'F':
|
|
|
|
|
d = uint32(c - 'A' + 10)
|
|
|
|
|
default:
|
|
|
|
|
Yyerror("non-hex character in escape sequence: %c", c)
|
2016-03-11 13:55:53 -08:00
|
|
|
l.ungetr()
|
2016-02-24 11:49:31 -08:00
|
|
|
return x
|
|
|
|
|
}
|
|
|
|
|
x = x*16 + d
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
return x
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|