2015-01-22 10:48:02 -08:00
|
|
|
// Copyright 2015 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 lex
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2021-04-15 23:05:49 -04:00
|
|
|
"internal/buildcfg"
|
2015-01-22 10:48:02 -08:00
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"text/scanner"
|
|
|
|
|
|
|
|
|
|
"cmd/asm/internal/flags"
|
2017-11-10 11:38:51 -08:00
|
|
|
"cmd/internal/objabi"
|
2016-12-09 17:15:05 -08:00
|
|
|
"cmd/internal/src"
|
2015-01-22 10:48:02 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Input is the main input: a stack of readers and some macro definitions.
|
|
|
|
|
// It also handles #include processing (by pushing onto the input stack)
|
|
|
|
|
// and parses and instantiates macro definitions.
|
|
|
|
|
type Input struct {
|
|
|
|
|
Stack
|
|
|
|
|
includes []string
|
|
|
|
|
beginningOfLine bool
|
|
|
|
|
ifdefStack []bool
|
|
|
|
|
macros map[string]*Macro
|
2015-01-30 09:57:11 -08:00
|
|
|
text string // Text of last token returned by Next.
|
|
|
|
|
peek bool
|
|
|
|
|
peekToken ScanToken
|
|
|
|
|
peekText string
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 16:02:54 -08:00
|
|
|
// NewInput returns an Input from the given path.
|
2023-06-30 16:33:49 -04:00
|
|
|
func NewInput(name string, compilingRuntime bool) *Input {
|
2015-01-22 10:48:02 -08:00
|
|
|
return &Input{
|
|
|
|
|
// include directories: look in source dir, then -I directories.
|
|
|
|
|
includes: append([]string{filepath.Dir(name)}, flags.I...),
|
|
|
|
|
beginningOfLine: true,
|
2023-06-30 16:33:49 -04:00
|
|
|
macros: predefine(flags.D, compilingRuntime),
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// predefine installs the macros set by the -D flag on the command line.
|
2023-06-30 16:33:49 -04:00
|
|
|
func predefine(defines flags.MultiFlag, compilingRuntime bool) map[string]*Macro {
|
2015-01-22 10:48:02 -08:00
|
|
|
macros := make(map[string]*Macro)
|
2020-12-23 19:49:39 -08:00
|
|
|
|
2021-04-06 08:25:01 -04:00
|
|
|
// Set macros for GOEXPERIMENTs so we can easily switch
|
|
|
|
|
// runtime assembly code based on them.
|
2023-06-30 16:33:49 -04:00
|
|
|
if compilingRuntime {
|
2022-03-16 16:25:47 -04:00
|
|
|
for _, exp := range buildcfg.Experiment.Enabled() {
|
2021-04-06 08:25:01 -04:00
|
|
|
// Define macro.
|
|
|
|
|
name := "GOEXPERIMENT_" + exp
|
all: explode GOEXPERIMENT=regabi into 5 sub-experiments
This separates GOEXPERIMENT=regabi into five sub-experiments:
regabiwrappers, regabig, regabireflect, regabidefer, and regabiargs.
Setting GOEXPERIMENT=regabi now implies the working subset of these
(currently, regabiwrappers, regabig, and regabireflect).
This simplifies testing, helps derisk the register ABI project,
and will also help with performance comparisons.
This replaces the -abiwrap flag to the compiler and linker with
the regabiwrappers experiment.
As part of this, regabiargs now enables registers for all calls
in the compiler. Previously, this was statically disabled in
regabiEnabledForAllCompilation, but now that we can control it
independently, this isn't necessary.
For #40724.
Change-Id: I5171e60cda6789031f2ef034cc2e7c5d62459122
Reviewed-on: https://go-review.googlesource.com/c/go/+/302070
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
2021-03-15 16:48:54 -04:00
|
|
|
macros[name] = &Macro{
|
|
|
|
|
name: name,
|
|
|
|
|
args: nil,
|
|
|
|
|
tokens: Tokenize("1"),
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-23 19:49:39 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-22 10:48:02 -08:00
|
|
|
for _, name := range defines {
|
|
|
|
|
value := "1"
|
|
|
|
|
i := strings.IndexRune(name, '=')
|
|
|
|
|
if i > 0 {
|
|
|
|
|
name, value = name[:i], name[i+1:]
|
|
|
|
|
}
|
2015-01-28 11:11:33 -08:00
|
|
|
tokens := Tokenize(name)
|
2015-01-22 10:48:02 -08:00
|
|
|
if len(tokens) != 1 || tokens[0].ScanToken != scanner.Ident {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "asm: parsing -D: %q is not a valid identifier name\n", tokens[0])
|
|
|
|
|
flags.Usage()
|
|
|
|
|
}
|
|
|
|
|
macros[name] = &Macro{
|
|
|
|
|
name: name,
|
|
|
|
|
args: nil,
|
2015-01-28 11:11:33 -08:00
|
|
|
tokens: Tokenize(value),
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return macros
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-17 13:46:46 -07:00
|
|
|
var panicOnError bool // For testing.
|
|
|
|
|
|
2015-01-22 10:48:02 -08:00
|
|
|
func (in *Input) Error(args ...interface{}) {
|
2015-09-17 13:46:46 -07:00
|
|
|
if panicOnError {
|
|
|
|
|
panic(fmt.Errorf("%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...)))
|
|
|
|
|
}
|
2015-01-22 10:48:02 -08:00
|
|
|
fmt.Fprintf(os.Stderr, "%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...))
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// expectText is like Error but adds "got XXX" where XXX is a quoted representation of the most recent token.
|
|
|
|
|
func (in *Input) expectText(args ...interface{}) {
|
2015-01-30 09:57:11 -08:00
|
|
|
in.Error(append(args, "; got", strconv.Quote(in.Stack.Text()))...)
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// enabled reports whether the input is enabled by an ifdef, or is at the top level.
|
|
|
|
|
func (in *Input) enabled() bool {
|
|
|
|
|
return len(in.ifdefStack) == 0 || in.ifdefStack[len(in.ifdefStack)-1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (in *Input) expectNewline(directive string) {
|
|
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok != '\n' {
|
|
|
|
|
in.expectText("expected newline after", directive)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (in *Input) Next() ScanToken {
|
2015-01-30 09:57:11 -08:00
|
|
|
if in.peek {
|
|
|
|
|
in.peek = false
|
|
|
|
|
tok := in.peekToken
|
|
|
|
|
in.text = in.peekText
|
|
|
|
|
return tok
|
|
|
|
|
}
|
2015-02-10 17:11:36 -08:00
|
|
|
// If we cannot generate a token after 100 macro invocations, we're in trouble.
|
2015-02-02 10:56:41 -08:00
|
|
|
// The usual case is caught by Push, below, but be safe.
|
2015-02-10 17:11:36 -08:00
|
|
|
for nesting := 0; nesting < 100; {
|
2015-01-22 10:48:02 -08:00
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
switch tok {
|
|
|
|
|
case '#':
|
|
|
|
|
if !in.beginningOfLine {
|
|
|
|
|
in.Error("'#' must be first item on line")
|
|
|
|
|
}
|
|
|
|
|
in.beginningOfLine = in.hash()
|
2020-06-29 17:08:49 -04:00
|
|
|
in.text = "#"
|
|
|
|
|
return '#'
|
|
|
|
|
|
2015-01-22 10:48:02 -08:00
|
|
|
case scanner.Ident:
|
|
|
|
|
// Is it a macro name?
|
|
|
|
|
name := in.Stack.Text()
|
|
|
|
|
macro := in.macros[name]
|
|
|
|
|
if macro != nil {
|
2015-02-10 17:11:36 -08:00
|
|
|
nesting++
|
2015-01-22 10:48:02 -08:00
|
|
|
in.invokeMacro(macro)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
default:
|
2015-09-17 13:46:46 -07:00
|
|
|
if tok == scanner.EOF && len(in.ifdefStack) > 0 {
|
|
|
|
|
// We're skipping text but have run out of input with no #endif.
|
|
|
|
|
in.Error("unclosed #ifdef or #ifndef")
|
|
|
|
|
}
|
2015-01-22 10:48:02 -08:00
|
|
|
in.beginningOfLine = tok == '\n'
|
|
|
|
|
if in.enabled() {
|
2015-01-30 09:57:11 -08:00
|
|
|
in.text = in.Stack.Text()
|
2015-01-22 10:48:02 -08:00
|
|
|
return tok
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
in.Error("recursive macro invocation")
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 09:57:11 -08:00
|
|
|
func (in *Input) Text() string {
|
|
|
|
|
return in.text
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 15:18:43 +00:00
|
|
|
// hash processes a # preprocessor directive. It reports whether it completes.
|
2015-01-22 10:48:02 -08:00
|
|
|
func (in *Input) hash() bool {
|
|
|
|
|
// We have a '#'; it must be followed by a known word (define, include, etc.).
|
|
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok != scanner.Ident {
|
|
|
|
|
in.expectText("expected identifier after '#'")
|
|
|
|
|
}
|
|
|
|
|
if !in.enabled() {
|
2015-09-03 22:49:18 +12:00
|
|
|
// Can only start including again if we are at #else or #endif but also
|
|
|
|
|
// need to keep track of nested #if[n]defs.
|
2015-01-22 10:48:02 -08:00
|
|
|
// We let #line through because it might affect errors.
|
2015-01-30 09:57:11 -08:00
|
|
|
switch in.Stack.Text() {
|
2015-09-03 22:49:18 +12:00
|
|
|
case "else", "endif", "ifdef", "ifndef", "line":
|
2015-01-22 10:48:02 -08:00
|
|
|
// Press on.
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-30 09:57:11 -08:00
|
|
|
switch in.Stack.Text() {
|
2015-01-22 10:48:02 -08:00
|
|
|
case "define":
|
|
|
|
|
in.define()
|
|
|
|
|
case "else":
|
|
|
|
|
in.else_()
|
|
|
|
|
case "endif":
|
|
|
|
|
in.endif()
|
|
|
|
|
case "ifdef":
|
|
|
|
|
in.ifdef(true)
|
|
|
|
|
case "ifndef":
|
|
|
|
|
in.ifdef(false)
|
|
|
|
|
case "include":
|
|
|
|
|
in.include()
|
|
|
|
|
case "line":
|
|
|
|
|
in.line()
|
|
|
|
|
case "undef":
|
|
|
|
|
in.undef()
|
|
|
|
|
default:
|
2015-01-30 09:57:11 -08:00
|
|
|
in.Error("unexpected token after '#':", in.Stack.Text())
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// macroName returns the name for the macro being referenced.
|
|
|
|
|
func (in *Input) macroName() string {
|
|
|
|
|
// We use the Stack's input method; no macro processing at this stage.
|
|
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok != scanner.Ident {
|
|
|
|
|
in.expectText("expected identifier after # directive")
|
|
|
|
|
}
|
|
|
|
|
// Name is alphanumeric by definition.
|
2015-01-30 09:57:11 -08:00
|
|
|
return in.Stack.Text()
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #define processing.
|
|
|
|
|
func (in *Input) define() {
|
|
|
|
|
name := in.macroName()
|
|
|
|
|
args, tokens := in.macroDefinition(name)
|
|
|
|
|
in.defineMacro(name, args, tokens)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// defineMacro stores the macro definition in the Input.
|
|
|
|
|
func (in *Input) defineMacro(name string, args []string, tokens []Token) {
|
|
|
|
|
if in.macros[name] != nil {
|
|
|
|
|
in.Error("redefinition of macro:", name)
|
|
|
|
|
}
|
|
|
|
|
in.macros[name] = &Macro{
|
|
|
|
|
name: name,
|
|
|
|
|
args: args,
|
|
|
|
|
tokens: tokens,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// macroDefinition returns the list of formals and the tokens of the definition.
|
|
|
|
|
// The argument list is nil for no parens on the definition; otherwise a list of
|
|
|
|
|
// formal argument names.
|
|
|
|
|
func (in *Input) macroDefinition(name string) ([]string, []Token) {
|
2015-02-13 16:55:33 -08:00
|
|
|
prevCol := in.Stack.Col()
|
2015-01-22 10:48:02 -08:00
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok == '\n' || tok == scanner.EOF {
|
2015-02-19 12:57:33 -08:00
|
|
|
return nil, nil // No definition for macro
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
var args []string
|
2015-02-13 16:55:33 -08:00
|
|
|
// The C preprocessor treats
|
|
|
|
|
// #define A(x)
|
|
|
|
|
// and
|
|
|
|
|
// #define A (x)
|
|
|
|
|
// distinctly: the first is a macro with arguments, the second without.
|
|
|
|
|
// Distinguish these cases using the column number, since we don't
|
|
|
|
|
// see the space itself. Note that text/scanner reports the position at the
|
|
|
|
|
// end of the token. It's where you are now, and you just read this token.
|
|
|
|
|
if tok == '(' && in.Stack.Col() == prevCol+1 {
|
2015-01-22 10:48:02 -08:00
|
|
|
// Macro has arguments. Scan list of formals.
|
|
|
|
|
acceptArg := true
|
|
|
|
|
args = []string{} // Zero length but not nil.
|
|
|
|
|
Loop:
|
|
|
|
|
for {
|
|
|
|
|
tok = in.Stack.Next()
|
|
|
|
|
switch tok {
|
|
|
|
|
case ')':
|
|
|
|
|
tok = in.Stack.Next() // First token of macro definition.
|
|
|
|
|
break Loop
|
|
|
|
|
case ',':
|
|
|
|
|
if acceptArg {
|
|
|
|
|
in.Error("bad syntax in definition for macro:", name)
|
|
|
|
|
}
|
|
|
|
|
acceptArg = true
|
|
|
|
|
case scanner.Ident:
|
|
|
|
|
if !acceptArg {
|
|
|
|
|
in.Error("bad syntax in definition for macro:", name)
|
|
|
|
|
}
|
|
|
|
|
arg := in.Stack.Text()
|
|
|
|
|
if i := lookup(args, arg); i >= 0 {
|
|
|
|
|
in.Error("duplicate argument", arg, "in definition for macro:", name)
|
|
|
|
|
}
|
|
|
|
|
args = append(args, arg)
|
|
|
|
|
acceptArg = false
|
|
|
|
|
default:
|
|
|
|
|
in.Error("bad definition for macro:", name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var tokens []Token
|
|
|
|
|
// Scan to newline. Backslashes escape newlines.
|
|
|
|
|
for tok != '\n' {
|
2015-09-17 13:46:46 -07:00
|
|
|
if tok == scanner.EOF {
|
2015-10-28 07:44:35 +01:00
|
|
|
in.Error("missing newline in definition for macro:", name)
|
2015-09-17 13:46:46 -07:00
|
|
|
}
|
2015-01-22 10:48:02 -08:00
|
|
|
if tok == '\\' {
|
|
|
|
|
tok = in.Stack.Next()
|
|
|
|
|
if tok != '\n' && tok != '\\' {
|
|
|
|
|
in.Error(`can only escape \ or \n in definition for macro:`, name)
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-30 09:57:11 -08:00
|
|
|
tokens = append(tokens, Make(tok, in.Stack.Text()))
|
2015-01-22 10:48:02 -08:00
|
|
|
tok = in.Stack.Next()
|
|
|
|
|
}
|
|
|
|
|
return args, tokens
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func lookup(args []string, arg string) int {
|
|
|
|
|
for i, a := range args {
|
|
|
|
|
if a == arg {
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// invokeMacro pushes onto the input Stack a Slice that holds the macro definition with the actual
|
|
|
|
|
// parameters substituted for the formals.
|
|
|
|
|
// Invoking a macro does not touch the PC/line history.
|
|
|
|
|
func (in *Input) invokeMacro(macro *Macro) {
|
2015-01-30 09:57:11 -08:00
|
|
|
// If the macro has no arguments, just substitute the text.
|
|
|
|
|
if macro.args == nil {
|
2016-12-09 17:15:05 -08:00
|
|
|
in.Push(NewSlice(in.Base(), in.Line(), macro.tokens))
|
2015-01-30 09:57:11 -08:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok != '(' {
|
|
|
|
|
// If the macro has arguments but is invoked without them, all we push is the macro name.
|
|
|
|
|
// First, put back the token.
|
|
|
|
|
in.peekToken = tok
|
|
|
|
|
in.peekText = in.text
|
|
|
|
|
in.peek = true
|
2016-12-09 17:15:05 -08:00
|
|
|
in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
|
2015-01-30 09:57:11 -08:00
|
|
|
return
|
|
|
|
|
}
|
2015-01-22 10:48:02 -08:00
|
|
|
actuals := in.argsFor(macro)
|
|
|
|
|
var tokens []Token
|
|
|
|
|
for _, tok := range macro.tokens {
|
|
|
|
|
if tok.ScanToken != scanner.Ident {
|
|
|
|
|
tokens = append(tokens, tok)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
substitution := actuals[tok.text]
|
|
|
|
|
if substitution == nil {
|
|
|
|
|
tokens = append(tokens, tok)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
tokens = append(tokens, substitution...)
|
|
|
|
|
}
|
2016-12-09 17:15:05 -08:00
|
|
|
in.Push(NewSlice(in.Base(), in.Line(), tokens))
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-30 09:57:11 -08:00
|
|
|
// argsFor returns a map from formal name to actual value for this argumented macro invocation.
|
|
|
|
|
// The opening parenthesis has been absorbed.
|
2015-01-22 10:48:02 -08:00
|
|
|
func (in *Input) argsFor(macro *Macro) map[string][]Token {
|
2015-01-29 16:33:36 -08:00
|
|
|
var args [][]Token
|
|
|
|
|
// One macro argument per iteration. Collect them all and check counts afterwards.
|
|
|
|
|
for argNum := 0; ; argNum++ {
|
|
|
|
|
tokens, tok := in.collectArgument(macro)
|
|
|
|
|
args = append(args, tokens)
|
|
|
|
|
if tok == ')' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Zero-argument macros are tricky.
|
|
|
|
|
if len(macro.args) == 0 && len(args) == 1 && args[0] == nil {
|
|
|
|
|
args = nil
|
|
|
|
|
} else if len(args) != len(macro.args) {
|
|
|
|
|
in.Error("wrong arg count for macro", macro.name)
|
|
|
|
|
}
|
|
|
|
|
argMap := make(map[string][]Token)
|
|
|
|
|
for i, arg := range args {
|
|
|
|
|
argMap[macro.args[i]] = arg
|
|
|
|
|
}
|
|
|
|
|
return argMap
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// collectArgument returns the actual tokens for a single argument of a macro.
|
|
|
|
|
// It also returns the token that terminated the argument, which will always
|
|
|
|
|
// be either ',' or ')'. The starting '(' has been scanned.
|
|
|
|
|
func (in *Input) collectArgument(macro *Macro) ([]Token, ScanToken) {
|
|
|
|
|
nesting := 0
|
2015-01-22 10:48:02 -08:00
|
|
|
var tokens []Token
|
|
|
|
|
for {
|
2015-01-29 16:33:36 -08:00
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok == scanner.EOF || tok == '\n' {
|
2015-01-22 10:48:02 -08:00
|
|
|
in.Error("unterminated arg list invoking macro:", macro.name)
|
|
|
|
|
}
|
2015-01-29 16:33:36 -08:00
|
|
|
if nesting == 0 && (tok == ')' || tok == ',') {
|
|
|
|
|
return tokens, tok
|
|
|
|
|
}
|
|
|
|
|
if tok == '(' {
|
|
|
|
|
nesting++
|
|
|
|
|
}
|
|
|
|
|
if tok == ')' {
|
|
|
|
|
nesting--
|
|
|
|
|
}
|
|
|
|
|
tokens = append(tokens, Make(tok, in.Stack.Text()))
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #ifdef and #ifndef processing.
|
|
|
|
|
func (in *Input) ifdef(truth bool) {
|
|
|
|
|
name := in.macroName()
|
|
|
|
|
in.expectNewline("#if[n]def")
|
2015-09-03 22:49:18 +12:00
|
|
|
if !in.enabled() {
|
|
|
|
|
truth = false
|
|
|
|
|
} else if _, defined := in.macros[name]; !defined {
|
2015-01-22 10:48:02 -08:00
|
|
|
truth = !truth
|
|
|
|
|
}
|
|
|
|
|
in.ifdefStack = append(in.ifdefStack, truth)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #else processing
|
|
|
|
|
func (in *Input) else_() {
|
|
|
|
|
in.expectNewline("#else")
|
|
|
|
|
if len(in.ifdefStack) == 0 {
|
|
|
|
|
in.Error("unmatched #else")
|
|
|
|
|
}
|
2015-09-03 22:49:18 +12:00
|
|
|
if len(in.ifdefStack) == 1 || in.ifdefStack[len(in.ifdefStack)-2] {
|
|
|
|
|
in.ifdefStack[len(in.ifdefStack)-1] = !in.ifdefStack[len(in.ifdefStack)-1]
|
|
|
|
|
}
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #endif processing.
|
|
|
|
|
func (in *Input) endif() {
|
|
|
|
|
in.expectNewline("#endif")
|
|
|
|
|
if len(in.ifdefStack) == 0 {
|
|
|
|
|
in.Error("unmatched #endif")
|
|
|
|
|
}
|
|
|
|
|
in.ifdefStack = in.ifdefStack[:len(in.ifdefStack)-1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #include processing.
|
|
|
|
|
func (in *Input) include() {
|
|
|
|
|
// Find and parse string.
|
|
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok != scanner.String {
|
|
|
|
|
in.expectText("expected string after #include")
|
|
|
|
|
}
|
2015-01-30 09:57:11 -08:00
|
|
|
name, err := strconv.Unquote(in.Stack.Text())
|
2015-01-22 10:48:02 -08:00
|
|
|
if err != nil {
|
|
|
|
|
in.Error("unquoting include file name: ", err)
|
|
|
|
|
}
|
|
|
|
|
in.expectNewline("#include")
|
|
|
|
|
// Push tokenizer for file onto stack.
|
|
|
|
|
fd, err := os.Open(name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
for _, dir := range in.includes {
|
|
|
|
|
fd, err = os.Open(filepath.Join(dir, name))
|
|
|
|
|
if err == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
in.Error("#include:", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
in.Push(NewTokenizer(name, fd, fd))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #line processing.
|
|
|
|
|
func (in *Input) line() {
|
|
|
|
|
// Only need to handle Plan 9 format: #line 337 "filename"
|
|
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok != scanner.Int {
|
|
|
|
|
in.expectText("expected line number after #line")
|
|
|
|
|
}
|
|
|
|
|
line, err := strconv.Atoi(in.Stack.Text())
|
|
|
|
|
if err != nil {
|
|
|
|
|
in.Error("error parsing #line (cannot happen):", err)
|
|
|
|
|
}
|
|
|
|
|
tok = in.Stack.Next()
|
|
|
|
|
if tok != scanner.String {
|
|
|
|
|
in.expectText("expected file name in #line")
|
|
|
|
|
}
|
|
|
|
|
file, err := strconv.Unquote(in.Stack.Text())
|
|
|
|
|
if err != nil {
|
|
|
|
|
in.Error("unquoting #line file name: ", err)
|
|
|
|
|
}
|
2015-02-03 10:41:16 -08:00
|
|
|
tok = in.Stack.Next()
|
|
|
|
|
if tok != '\n' {
|
|
|
|
|
in.Error("unexpected token at end of #line: ", tok)
|
|
|
|
|
}
|
2018-02-22 17:24:19 -08:00
|
|
|
pos := src.MakePos(in.Base(), uint(in.Line())+1, 1) // +1 because #line nnn means line nnn starts on next line
|
|
|
|
|
in.Stack.SetBase(src.NewLinePragmaBase(pos, file, objabi.AbsFile(objabi.WorkingDir(), file, *flags.TrimPath), uint(line), 1))
|
2015-01-22 10:48:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #undef processing
|
|
|
|
|
func (in *Input) undef() {
|
|
|
|
|
name := in.macroName()
|
|
|
|
|
if in.macros[name] == nil {
|
|
|
|
|
in.Error("#undef for undefined macro:", name)
|
|
|
|
|
}
|
|
|
|
|
// Newline must be next.
|
|
|
|
|
tok := in.Stack.Next()
|
|
|
|
|
if tok != '\n' {
|
|
|
|
|
in.Error("syntax error in #undef for macro:", name)
|
|
|
|
|
}
|
|
|
|
|
delete(in.macros, name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (in *Input) Push(r TokenReader) {
|
|
|
|
|
if len(in.tr) > 100 {
|
|
|
|
|
in.Error("input recursion")
|
|
|
|
|
}
|
|
|
|
|
in.Stack.Push(r)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (in *Input) Close() {
|
|
|
|
|
}
|