modernc.org/cc@v1.0.1/cpp.go (about)

     1  // Copyright 2016 The CC Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cc // import "modernc.org/cc"
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"strconv"
    13  	"strings"
    14  
    15  	"modernc.org/golex/lex"
    16  	"modernc.org/mathutil"
    17  	"modernc.org/xc"
    18  )
    19  
    20  var (
    21  	_ tokenReader = (*tokenBuf)(nil)
    22  	_ tokenReader = (*tokenPipe)(nil)
    23  )
    24  
    25  const (
    26  	maxIncludeLevel = 100
    27  	sentinel        = -1
    28  )
    29  
    30  var (
    31  	protectedMacros = map[int]bool{
    32  		idDate:             true,
    33  		idDefined:          true,
    34  		idFile:             true,
    35  		idLine:             true,
    36  		idSTDC:             true,
    37  		idSTDCHosted:       true,
    38  		idSTDCMBMightNeqWc: true,
    39  		idSTDCVersion:      true,
    40  		idTime:             true,
    41  		idVAARGS:           true,
    42  	}
    43  )
    44  
    45  // Macro represents a C preprocessor macro.
    46  type Macro struct {
    47  	Args      []int       // Numeric IDs of argument identifiers.
    48  	DefTok    xc.Token    // Macro name definition token.
    49  	IsFnLike  bool        // Whether the macro is function like.
    50  	Type      Type        // Non nil if macro expands to a constant expression.
    51  	Value     interface{} // Non nil if macro expands to a constant expression.
    52  	ellipsis  bool        // Macro definition uses the idList, ... notation.
    53  	ellipsis2 bool        // Macro definition uses the idList... notation.
    54  	nonRepl   []bool      // Non replaceable, due to # or ##, arguments of a fn-like macro.
    55  	repl      PPTokenList //
    56  }
    57  
    58  // ReplacementToks returns the tokens that replace m.
    59  func (m *Macro) ReplacementToks() (r []xc.Token) { return decodeTokens(m.repl, nil, false) }
    60  
    61  func (m *Macro) findArg(nm int) int {
    62  	for i, v := range m.Args {
    63  		if v == nm {
    64  			return i
    65  		}
    66  	}
    67  
    68  	if m.ellipsis && nm == idVAARGS {
    69  		return len(m.Args)
    70  	}
    71  
    72  	return -1
    73  }
    74  
    75  type macros struct {
    76  	m     map[int]*Macro
    77  	pp    *pp
    78  	stack map[int][]*Macro
    79  }
    80  
    81  func newMacros() *macros {
    82  	return &macros{
    83  		m:     map[int]*Macro{},
    84  		stack: map[int][]*Macro{},
    85  	}
    86  }
    87  
    88  func (m *macros) macros() map[int]*Macro {
    89  	p := m.pp
    90  	defer func(ie bool) {
    91  		p.report.IgnoreErrors = ie
    92  	}(p.report.IgnoreErrors)
    93  
    94  	p.report.IgnoreErrors = true
    95  	r := map[int]*Macro{}
    96  	for id, macro := range m.m {
    97  		r[id] = macro
    98  
    99  		if macro.IsFnLike {
   100  			continue
   101  		}
   102  
   103  		rl := macro.repl
   104  		if rl == 0 {
   105  			macro.Value = true // #define foo -> foo: true.
   106  			macro.Type = p.model.BoolType
   107  			continue
   108  		}
   109  
   110  		macro.Value, macro.Type = p.lx.parsePPConstExpr0(rl, p)
   111  	}
   112  	return r
   113  }
   114  
   115  type tokenReader interface {
   116  	eof(more bool) bool
   117  	peek() xc.Token
   118  	read() xc.Token
   119  	unget([]xc.Token)
   120  }
   121  
   122  type tokenBuf struct {
   123  	toks []xc.Token
   124  }
   125  
   126  // Implements tokenReader.
   127  func (t *tokenBuf) eof(bool) bool { return len(t.toks) == 0 }
   128  
   129  // Implements tokenReader.
   130  func (t *tokenBuf) peek() xc.Token { return t.toks[0] }
   131  
   132  // Implements tokenReader.
   133  func (t *tokenBuf) read() xc.Token { r := t.peek(); t.toks = t.toks[1:]; return r }
   134  
   135  // Implements tokenReader.
   136  func (t *tokenBuf) unget(toks []xc.Token) { t.toks = append(toks[:len(toks):len(toks)], t.toks...) }
   137  
   138  type tokenPipe struct {
   139  	ack     chan struct{}
   140  	ackMore bool
   141  	closed  bool
   142  	in      []xc.Token
   143  	last    xc.Token
   144  	out     []xc.Token
   145  	r       chan []xc.Token
   146  	w       chan []xc.Token
   147  }
   148  
   149  // Implements tokenReader.
   150  func (t *tokenPipe) eof(more bool) bool {
   151  again:
   152  	if len(t.in) != 0 {
   153  		return false
   154  	}
   155  
   156  	if t.closed {
   157  		return true
   158  	}
   159  
   160  	t.flush(false)
   161  	if !more {
   162  		return true
   163  	}
   164  
   165  	if t.ackMore {
   166  		t.ack <- struct{}{}
   167  	}
   168  	var ok bool
   169  	if t.in, ok = <-t.r; !ok {
   170  		t.closed = true
   171  		return true
   172  	}
   173  
   174  	if len(t.in) != 0 && t.last.Rune == ' ' && t.in[0].Rune == ' ' {
   175  		t.in = t.in[1:]
   176  		goto again
   177  	}
   178  
   179  	if n := len(t.in); n > 1 && t.in[n-1].Rune == ' ' && t.in[n-2].Rune == ' ' {
   180  		t.in = t.in[:n-1]
   181  		goto again
   182  	}
   183  
   184  	return false
   185  }
   186  
   187  // Implements tokenReader.
   188  func (t *tokenPipe) peek() xc.Token { return t.in[0] }
   189  
   190  // Implements tokenReader.
   191  func (t *tokenPipe) read() xc.Token {
   192  	r := t.peek()
   193  	t.in = t.in[1:]
   194  	t.last = r
   195  	return r
   196  }
   197  
   198  // Implements tokenReader.
   199  func (t *tokenPipe) unget(toks []xc.Token) {
   200  	t.in = append(toks[:len(toks):len(toks)], t.in...)
   201  }
   202  
   203  func (t *tokenPipe) flush(final bool) {
   204  	t.out = trimSpace(t.out, false)
   205  	if n := len(t.out); !final && n != 0 {
   206  		if tok := t.out[n-1]; tok.Rune == STRINGLITERAL || tok.Rune == LONGSTRINGLITERAL {
   207  			// Accumulate lines b/c of possible string concatenation of preprocessing phase 6.
   208  			return
   209  		}
   210  	}
   211  
   212  	// Preproc phase 6. Adjacent string literal tokens are concatenated.
   213  	w := 0
   214  	for r := 0; r < len(t.out); r++ {
   215  		v := t.out[r]
   216  		switch v.Rune {
   217  		case IDENTIFIER_NONREPL:
   218  			v.Rune = IDENTIFIER
   219  			t.out[w] = v
   220  			w++
   221  		case STRINGLITERAL, LONGSTRINGLITERAL:
   222  			to := r
   223  		loop:
   224  			for to < len(t.out)-1 {
   225  				switch t.out[to+1].Rune {
   226  				case STRINGLITERAL, LONGSTRINGLITERAL, ' ':
   227  					to++
   228  				default:
   229  					break loop
   230  				}
   231  			}
   232  			for t.out[to].Rune == ' ' {
   233  				to--
   234  			}
   235  			if to == r {
   236  				t.out[w] = v
   237  				w++
   238  				break
   239  			}
   240  
   241  			var buf bytes.Buffer
   242  			s := v.S()
   243  			s = s[:len(s)-1] // Remove trailing "
   244  			buf.Write(s)
   245  			for i := r + 1; i <= to; i++ {
   246  				if t.out[i].Rune == ' ' {
   247  					continue
   248  				}
   249  
   250  				s = dict.S(t.out[i].Val)
   251  				s = s[1 : len(s)-1] // Remove leading and trailing "
   252  				buf.Write(s)
   253  			}
   254  			r = to
   255  			buf.WriteByte('"')
   256  			v.Val = dict.ID(buf.Bytes())
   257  			fallthrough
   258  		default:
   259  			t.out[w] = v
   260  			w++
   261  		}
   262  	}
   263  	t.out = t.out[:w]
   264  	if w == 0 {
   265  		return
   266  	}
   267  
   268  	t.w <- t.out
   269  	t.out = nil
   270  }
   271  
   272  type pp struct {
   273  	ack                chan struct{}      // Must be unbuffered.
   274  	expandingMacros    map[int]int        //
   275  	in                 chan []xc.Token    // Must be unbuffered.
   276  	includeLevel       int                //
   277  	includedSearchPath string             //
   278  	includes           []string           //
   279  	lx                 *lexer             //
   280  	macros             *macros            //
   281  	model              *Model             //
   282  	ppf                *PreprocessingFile //
   283  	protectMacros      bool               //
   284  	report             *xc.Report         //
   285  	sysIncludes        []string           //
   286  	tweaks             *tweaks            //
   287  }
   288  
   289  func newPP(ch chan []xc.Token, includes, sysIncludes []string, macros *macros, protectMacros bool, model *Model, report *xc.Report, tweaks *tweaks) *pp {
   290  	var err error
   291  	if includes, err = dedupAbsPaths(append(includes[:len(includes):len(includes)], sysIncludes...)); err != nil {
   292  		report.Err(0, "%s", err)
   293  		return nil
   294  	}
   295  	pp := &pp{
   296  		ack:             make(chan struct{}),
   297  		expandingMacros: map[int]int{},
   298  		in:              make(chan []xc.Token),
   299  		includes:        includes,
   300  		lx:              newSimpleLexer(nil, report, tweaks),
   301  		macros:          macros,
   302  		model:           model,
   303  		protectMacros:   protectMacros,
   304  		report:          report,
   305  		sysIncludes:     sysIncludes,
   306  		tweaks:          tweaks,
   307  	}
   308  	macros.pp = pp
   309  	pp.lx.model = model
   310  	model.initialize(pp.lx)
   311  	go pp.pp2(ch)
   312  	return pp
   313  }
   314  
   315  func (p *pp) pp2(ch chan []xc.Token) {
   316  	pipe := &tokenPipe{ack: p.ack, r: p.in, w: ch}
   317  	for !pipe.eof(true) {
   318  		pipe.ackMore = true
   319  		p.expand(pipe, false, func(toks []xc.Token) { pipe.out = append(pipe.out, toks...) })
   320  		pipe.ackMore = false
   321  		p.ack <- struct{}{}
   322  	}
   323  	pipe.flush(true)
   324  	p.ack <- struct{}{}
   325  }
   326  
   327  func (p *pp) checkCompatibleReplacementTokenList(tok xc.Token, oldList, newList PPTokenList) {
   328  	ex := trimSpace(decodeTokens(oldList, nil, true), false)
   329  	toks := trimSpace(decodeTokens(newList, nil, true), false)
   330  
   331  	if g, e := len(toks), len(ex); g != e && len(ex) > 0 {
   332  		p.report.ErrTok(tok, "cannot redefine macro using a replacement list of different length")
   333  		return
   334  	}
   335  
   336  	if len(toks) == 0 || len(ex) == 0 {
   337  		return
   338  	}
   339  
   340  	if g, e := whitespace(toks), whitespace(ex); !bytes.Equal(g, e) {
   341  		p.report.ErrTok(tok, "cannot redefine macro, whitespace differs")
   342  	}
   343  
   344  	for i, g := range toks {
   345  		if e := ex[i]; g.Rune != e.Rune || g.Val != e.Val {
   346  			p.report.ErrTok(tok, "cannot redefine macro using a different replacement list")
   347  			return
   348  		}
   349  	}
   350  }
   351  
   352  func (p *pp) defineMacro(tok xc.Token, repl PPTokenList) {
   353  	nm := tok.Val
   354  	if protectedMacros[nm] && p.protectMacros {
   355  		p.report.ErrTok(tok, "cannot define protected macro")
   356  		return
   357  	}
   358  
   359  	m := p.macros.m[nm]
   360  	if m == nil {
   361  		if debugMacros {
   362  			toks := trimSpace(decodeTokens(repl, nil, true), false)
   363  			var a [][]byte
   364  			for _, v := range toks {
   365  				a = append(a, xc.Dict.S(tokVal(v)))
   366  			}
   367  			fmt.Fprintf(os.Stderr, "%s: #define %s %s\n", tok.Position(), tok.S(), bytes.Join(a, nil))
   368  		}
   369  		p.macros.m[nm] = &Macro{DefTok: tok, repl: repl}
   370  		return
   371  	}
   372  
   373  	if m.IsFnLike {
   374  		p.report.ErrTok(tok, "cannot redefine a function-like macro using an object-like macro")
   375  		return
   376  	}
   377  
   378  	p.checkCompatibleReplacementTokenList(tok, m.repl, repl)
   379  }
   380  
   381  func (p *pp) defineFnMacro(tok xc.Token, il *IdentifierList, repl PPTokenList, ellipsis, ellipsis2 bool) {
   382  	nm0 := tok.S()
   383  	nm := dict.ID(nm0[:len(nm0)-1])
   384  	if protectedMacros[nm] && p.protectMacros {
   385  		p.report.ErrTok(tok, "cannot define protected macro %s", xc.Dict.S(nm))
   386  		return
   387  	}
   388  
   389  	var args []int
   390  	for ; il != nil; il = il.IdentifierList {
   391  		tok := il.Token2
   392  		if !tok.IsValid() {
   393  			tok = il.Token
   394  		}
   395  		args = append(args, tok.Val)
   396  	}
   397  	m := p.macros.m[nm]
   398  	defTok := tok
   399  	defTok.Rune = IDENTIFIER
   400  	defTok.Val = nm
   401  	if m == nil {
   402  		replToks := decodeTokens(repl, nil, false)
   403  		if debugMacros {
   404  			toks := trimSpace(replToks, false)
   405  			var p [][]byte
   406  			for _, v := range args {
   407  				p = append(p, xc.Dict.S(v))
   408  			}
   409  			var a [][]byte
   410  			for _, v := range toks {
   411  				a = append(a, xc.Dict.S(tokVal(v)))
   412  			}
   413  			fmt.Fprintf(os.Stderr, "%s: #define %s%s) %s\n", tok.Position(), tok.S(), bytes.Join(p, []byte(", ")), bytes.Join(a, nil))
   414  		}
   415  		nonRepl := make([]bool, len(args))
   416  		mp := map[int]struct{}{}
   417  		for i, v := range replToks {
   418  			switch v.Rune {
   419  			case PPPASTE:
   420  				if i > 0 {
   421  					if tok := replToks[i-1]; tok.Rune == IDENTIFIER {
   422  						mp[tok.Val] = struct{}{}
   423  					}
   424  				}
   425  				fallthrough
   426  			case '#':
   427  				if i < len(replToks)-1 {
   428  					if tok := replToks[i+1]; tok.Rune == IDENTIFIER {
   429  						mp[tok.Val] = struct{}{}
   430  					}
   431  				}
   432  			}
   433  		}
   434  		m := &Macro{Args: args, DefTok: defTok, IsFnLike: true, repl: repl, ellipsis: ellipsis, ellipsis2: ellipsis2}
   435  		for nm := range mp {
   436  			if i := m.findArg(nm); i >= 0 && i < len(nonRepl) {
   437  				nonRepl[i] = true
   438  			}
   439  		}
   440  		m.nonRepl = nonRepl
   441  		p.macros.m[nm] = m
   442  		return
   443  	}
   444  
   445  	if !m.IsFnLike {
   446  		p.report.ErrTok(tok, "cannot redefine an object-like macro %s using a function-like macro", xc.Dict.S(nm))
   447  		return
   448  	}
   449  
   450  	if g, e := len(args), len(m.Args); g != e {
   451  		p.report.ErrTok(tok, "cannot redefine macro %s: number of arguments differ", xc.Dict.S(nm))
   452  		return
   453  	}
   454  
   455  	for i, g := range args {
   456  		if e := m.Args[i]; g != e {
   457  			p.report.ErrTok(tok, "cannot redefine macro %s: argument names differ", xc.Dict.S(nm))
   458  			return
   459  		}
   460  	}
   461  
   462  	p.checkCompatibleReplacementTokenList(tok, m.repl, repl)
   463  }
   464  
   465  func (p *pp) expand(r tokenReader, handleDefined bool, w func([]xc.Token)) {
   466  	for !r.eof(false) {
   467  		tok := r.read()
   468  		switch tok.Rune {
   469  		case sentinel:
   470  			p.expandingMacros[tok.Val]--
   471  		case IDENTIFIER:
   472  			if tok.Val == idFile {
   473  				tok.Rune = STRINGLITERAL
   474  				tok.Val = dict.SID(fmt.Sprintf("%q", tok.Position().Filename))
   475  				w([]xc.Token{tok})
   476  				continue
   477  			}
   478  
   479  			if tok.Val == idLine && !p.tweaks.disablePredefinedLineMacro {
   480  				tok.Rune = INTCONST
   481  				tok.Val = dict.SID(strconv.Itoa(position(tok.Pos()).Line))
   482  				w([]xc.Token{tok})
   483  				continue
   484  			}
   485  
   486  			if handleDefined && tok.Val == idDefined {
   487  				p.expandDefined(tok, r, w)
   488  				continue
   489  			}
   490  
   491  			m := p.macros.m[tok.Val]
   492  			if m == nil {
   493  				w([]xc.Token{tok})
   494  				continue
   495  			}
   496  
   497  			p.expandMacro(tok, r, m, handleDefined, w)
   498  		default:
   499  			w([]xc.Token{tok})
   500  		}
   501  	}
   502  }
   503  
   504  func (p *pp) expandDefined(tok xc.Token, r tokenReader, w func([]xc.Token)) {
   505  again:
   506  	if r.eof(false) {
   507  		p.report.ErrTok(tok, "'defined' with no argument")
   508  		return
   509  	}
   510  
   511  	switch tok = r.read(); tok.Rune {
   512  	case ' ':
   513  		goto again
   514  	case '(': // defined (IDENTIFIER)
   515  	again2:
   516  		if r.eof(false) {
   517  			p.report.ErrTok(tok, "'defined' with no argument")
   518  			return
   519  		}
   520  
   521  		tok = r.read()
   522  		switch tok.Rune {
   523  		case IDENTIFIER:
   524  			v := tok
   525  			v.Rune = INTCONST
   526  			if p.macros.m[tok.Val] != nil {
   527  				v.Val = id1
   528  			} else {
   529  				v.Val = id0
   530  			}
   531  
   532  		again3:
   533  			if r.eof(false) {
   534  				p.report.ErrTok(tok, "must be followed by ')'")
   535  				return
   536  			}
   537  
   538  			tok = r.read()
   539  			if tok.Rune == ' ' {
   540  				goto again3
   541  			}
   542  
   543  			if tok.Rune != ')' {
   544  				p.report.ErrTok(tok, "expected ')'")
   545  				return
   546  			}
   547  
   548  			w([]xc.Token{v})
   549  		case ' ':
   550  			goto again2
   551  		default:
   552  			p.report.ErrTok(tok, "expected identifier")
   553  			return
   554  		}
   555  	case IDENTIFIER:
   556  		v := tok
   557  		v.Rune = INTCONST
   558  		if p.macros.m[tok.Val] != nil {
   559  			v.Val = id1
   560  		} else {
   561  			v.Val = id0
   562  		}
   563  
   564  		w([]xc.Token{v})
   565  	default:
   566  		panic(PrettyString(tok))
   567  	}
   568  }
   569  
   570  func (p *pp) expandMacro(tok xc.Token, r tokenReader, m *Macro, handleDefined bool, w func([]xc.Token)) {
   571  	nm := tok.Val
   572  	if m.IsFnLike {
   573  		p.expandFnMacro(tok, r, m, handleDefined, w)
   574  		return
   575  	}
   576  
   577  	repl := trimSpace(normalizeToks(decodeTokens(m.repl, nil, true)), false)
   578  	repl = pasteToks(repl)
   579  	pos := tok.Pos()
   580  	for i, v := range repl {
   581  		repl[i].Char = lex.NewChar(pos, v.Rune)
   582  	}
   583  	tok.Rune = sentinel
   584  	p.expandingMacros[nm]++
   585  	y := append(p.sanitize(p.expandLineNo(p.pragmas(repl))), tok)
   586  	r.unget(y)
   587  }
   588  
   589  func trimSpace(toks []xc.Token, removeTrailingComma bool) []xc.Token {
   590  	if len(toks) == 0 {
   591  		return nil
   592  	}
   593  
   594  	if removeTrailingComma {
   595  		if tok := toks[len(toks)-1]; tok.Rune == ',' {
   596  			toks = toks[:len(toks)-1]
   597  		}
   598  	}
   599  	for len(toks) != 0 && toks[0].Rune == ' ' {
   600  		toks = toks[1:]
   601  	}
   602  	for len(toks) != 0 && toks[len(toks)-1].Rune == ' ' {
   603  		toks = toks[:len(toks)-1]
   604  	}
   605  	return toks
   606  }
   607  
   608  func (p *pp) pragmas(toks []xc.Token) []xc.Token {
   609  	var r []xc.Token
   610  	for len(toks) != 0 {
   611  		switch tok := toks[0]; {
   612  		case tok.Rune == IDENTIFIER && tok.Val == idPragma:
   613  			toks = toks[1:]
   614  			for len(toks) != 0 && toks[0].Rune == ' ' {
   615  				toks = toks[1:]
   616  			}
   617  			if len(toks) == 0 {
   618  				p.report.ErrTok(tok, "malformed _Pragma unary operator expression.")
   619  				return r
   620  			}
   621  
   622  			if toks[0].Rune != '(' {
   623  				p.report.ErrTok(toks[0], "expected '('")
   624  				return r
   625  			}
   626  
   627  			toks = toks[1:]
   628  			for len(toks) != 0 && toks[0].Rune == ' ' {
   629  				toks = toks[1:]
   630  			}
   631  			if len(toks) == 0 {
   632  				p.report.ErrTok(tok, "malformed _Pragma unary operator expression.")
   633  				return r
   634  			}
   635  
   636  			if toks[0].Rune != STRINGLITERAL && toks[0].Rune != LONGSTRINGLITERAL {
   637  				p.report.ErrTok(toks[0], "expected string literal or long string literal")
   638  				return r
   639  			}
   640  
   641  			toks = toks[1:]
   642  			for len(toks) != 0 && toks[0].Rune == ' ' {
   643  				toks = toks[1:]
   644  			}
   645  			if len(toks) == 0 {
   646  				p.report.ErrTok(tok, "malformed _Pragma unary operator expression.")
   647  				return r
   648  			}
   649  
   650  			if toks[0].Rune != ')' {
   651  				p.report.ErrTok(toks[0], "expected ')'")
   652  				return r
   653  			}
   654  
   655  			toks = toks[1:]
   656  		default:
   657  			r = append(r, tok)
   658  			toks = toks[1:]
   659  		}
   660  	}
   661  	return r
   662  }
   663  
   664  func (p *pp) sanitize(toks []xc.Token) []xc.Token {
   665  	w := 0
   666  	for _, v := range toks {
   667  		switch v.Rune {
   668  		case 0:
   669  			// nop
   670  		case IDENTIFIER:
   671  			if p.expandingMacros[v.Val] != 0 {
   672  				v.Rune = IDENTIFIER_NONREPL
   673  			}
   674  			fallthrough
   675  		default:
   676  			toks[w] = v
   677  			w++
   678  		}
   679  	}
   680  	return toks[:w]
   681  }
   682  
   683  func pasteToks(toks []xc.Token) []xc.Token {
   684  	for i := 0; i < len(toks); {
   685  		switch tok := toks[i]; tok.Rune {
   686  		case PPPASTE:
   687  			var b []byte
   688  			var r rune
   689  			var v int
   690  			if i > 0 {
   691  				i--
   692  				t := toks[i]
   693  				r = t.Rune
   694  				if r == IDENTIFIER_NONREPL {
   695  					// testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/compile/981001-3.c
   696  					r = IDENTIFIER
   697  				}
   698  				v = t.Val
   699  				b = append(b, xc.Dict.S(tokVal(t))...)
   700  				toks = append(toks[:i], toks[i+1:]...) // Remove left arg.
   701  			}
   702  			if i < len(toks)-1 {
   703  				i++
   704  				t := toks[i]
   705  				switch {
   706  				case r == 0:
   707  					r = t.Rune
   708  				case r == IDENTIFIER && v == idL:
   709  					switch t.Rune {
   710  					case CHARCONST:
   711  						r = LONGCHARCONST
   712  					case STRINGLITERAL:
   713  						r = LONGSTRINGLITERAL
   714  					}
   715  				}
   716  				b = append(b, xc.Dict.S(tokVal(t))...)
   717  				toks = append(toks[:i], toks[i+1:]...) // Remove right arg.
   718  				i--
   719  			}
   720  			tok.Rune = r
   721  			tok.Val = xc.Dict.ID(b)
   722  			if tok.Rune < 0x80 && tok.Val > 0x80 {
   723  				tok.Rune = PPOTHER
   724  			}
   725  			toks[i] = tok
   726  		default:
   727  			i++
   728  		}
   729  	}
   730  	return toks
   731  }
   732  
   733  func (p *pp) expandLineNo(toks []xc.Token) []xc.Token {
   734  	for i, v := range toks {
   735  		if v.Rune == IDENTIFIER && v.Val == idLine && !p.tweaks.disablePredefinedLineMacro {
   736  			v.Rune = INTCONST
   737  			v.Val = dict.SID(strconv.Itoa(position(v.Pos()).Line))
   738  			toks[i] = v
   739  		}
   740  	}
   741  	return toks
   742  }
   743  
   744  func normalizeToks(toks []xc.Token) []xc.Token {
   745  	if len(toks) == 0 {
   746  		return toks
   747  	}
   748  
   749  	for i := 0; i < len(toks); {
   750  		switch toks[i].Rune {
   751  		case PPPASTE:
   752  			if i > 0 && toks[i-1].Rune == ' ' {
   753  				i--
   754  				toks = append(toks[:i], toks[i+1:]...)
   755  				break
   756  			}
   757  
   758  			fallthrough
   759  		case '#':
   760  			if i < len(toks)-1 && toks[i+1].Rune == ' ' {
   761  				j := i + 1
   762  				toks = append(toks[:j], toks[j+1:]...)
   763  				break
   764  			}
   765  
   766  			fallthrough
   767  		default:
   768  			i++
   769  		}
   770  	}
   771  	return toks
   772  }
   773  
   774  func (p *pp) expandFnMacro(tok xc.Token, r tokenReader, m *Macro, handleDefined bool, w func([]xc.Token)) {
   775  	nm := tok.Val
   776  	var sentinels []xc.Token
   777  again:
   778  	if r.eof(true) {
   779  		r.unget(sentinels)
   780  		w([]xc.Token{tok})
   781  		return
   782  	}
   783  
   784  	switch c := r.peek().Rune; {
   785  	case c == ' ':
   786  		r.read()
   787  		goto again
   788  	case c == sentinel:
   789  		s := r.read()
   790  		sentinels = append([]xc.Token{s}, sentinels...)
   791  		goto again
   792  	case c != '(': // != name()
   793  		r.unget(sentinels)
   794  		w([]xc.Token{tok})
   795  		return
   796  	}
   797  
   798  	args := p.parseMacroArgs(r)
   799  	if g, e := len(args), len(m.Args); g != e {
   800  		switch {
   801  		case g == 1 && e == 0 && len(args[0]) == 0:
   802  			// Spacial case: Handling of empty args to macros with
   803  			// one parameter makes it non distinguishable of
   804  			// passing no argument to a macro with no parameters.
   805  
   806  			// ok, nop.
   807  		case m.ellipsis:
   808  			if g < e {
   809  				p.report.ErrTok(tok, "not enough macro arguments, expected at least %v", e+1)
   810  				return
   811  			}
   812  
   813  			for i := e + 1; i < len(args); i++ {
   814  				args[e] = append(args[e], args[i]...)
   815  			}
   816  			args = args[:e+1]
   817  		case m.ellipsis2:
   818  			if g < e {
   819  				p.report.ErrTok(tok, "not enough macro arguments, expected at least %v", e)
   820  				return
   821  			}
   822  
   823  			for i := e; i < len(args); i++ {
   824  				args[e-1] = append(args[e-1], args[i]...)
   825  			}
   826  			args = args[:e]
   827  		default:
   828  			p.report.ErrTok(tok, "macro argument count mismatch: got %v, expected %v", g, e)
   829  			return
   830  		}
   831  	}
   832  
   833  	for i, arg := range args {
   834  		args[i] = trimSpace(arg, true)
   835  	}
   836  	for i, arg := range args {
   837  		args[i] = nil
   838  		toks := p.expandLineNo(arg)
   839  		if i < len(m.nonRepl) && m.nonRepl[i] {
   840  			if len(toks) != 0 {
   841  				args[i] = toks
   842  			}
   843  			continue
   844  		}
   845  
   846  		p.expand(&tokenBuf{toks}, handleDefined, func(toks []xc.Token) { args[i] = append(args[i], toks...) })
   847  	}
   848  	repl := trimSpace(normalizeToks(decodeTokens(m.repl, nil, true)), false)
   849  	for i, v := range repl {
   850  		repl[i].Char = lex.NewChar(tok.Pos(), v.Rune)
   851  	}
   852  	var r0 []xc.Token
   853  next:
   854  	for i, tok := range repl {
   855  		switch tok.Rune {
   856  		case IDENTIFIER:
   857  			if ia := m.findArg(tok.Val); ia >= 0 {
   858  				if i > 0 && repl[i-1].Rune == '#' {
   859  					r0 = append(r0[:len(r0)-1], stringify(args[ia]))
   860  					continue next
   861  				}
   862  
   863  				var arg []xc.Token
   864  				if ia < len(args) {
   865  					arg = args[ia]
   866  				}
   867  				if len(arg) == 0 {
   868  					arg = []xc.Token{{}}
   869  				}
   870  				r0 = append(r0, arg...)
   871  
   872  				continue next
   873  			}
   874  
   875  			r0 = append(r0, tok)
   876  		default:
   877  			r0 = append(r0, tok)
   878  		}
   879  	}
   880  
   881  	tok.Rune = sentinel
   882  	sentinels = append([]xc.Token{tok}, sentinels...)
   883  	p.expandingMacros[nm]++
   884  	y := append(p.sanitize(p.pragmas(p.expandLineNo(pasteToks(r0)))), sentinels...)
   885  	r.unget(y)
   886  }
   887  
   888  func stringify(toks []xc.Token) xc.Token {
   889  	toks = trimSpace(toks, false)
   890  	if len(toks) == 0 || (toks[0] == xc.Token{}) {
   891  		return xc.Token{Char: lex.NewChar(0, STRINGLITERAL), Val: idEmptyString}
   892  	}
   893  
   894  	s := []byte{'"'}
   895  	for _, tok := range toks {
   896  		switch tok.Rune {
   897  		case CHARCONST, STRINGLITERAL, LONGSTRINGLITERAL, LONGCHARCONST:
   898  			for _, c := range tok.S() {
   899  				switch c {
   900  				case '"', '\\':
   901  					s = append(s, '\\', c)
   902  				default:
   903  					s = append(s, c)
   904  				}
   905  			}
   906  		default:
   907  			s = append(s, xc.Dict.S(tokVal(tok))...)
   908  		}
   909  	}
   910  	s = append(s, '"')
   911  	r := xc.Token{Char: lex.NewChar(toks[0].Pos(), STRINGLITERAL), Val: dict.ID(s)}
   912  	return r
   913  }
   914  
   915  func whitespace(toks []xc.Token) []byte {
   916  	if len(toks) < 2 {
   917  		return nil
   918  	}
   919  
   920  	r := make([]byte, 0, len(toks)-1)
   921  	ltok := toks[0]
   922  	for _, tok := range toks[1:] {
   923  		if ltok.Rune == ' ' {
   924  			continue
   925  		}
   926  
   927  		switch {
   928  		case tok.Rune == ' ':
   929  			r = append(r, 1)
   930  		default:
   931  			r = append(r, 0)
   932  		}
   933  		ltok = tok
   934  	}
   935  	return r
   936  }
   937  
   938  func (p *pp) parseMacroArgs(r tokenReader) (args [][]xc.Token) {
   939  	if r.eof(true) {
   940  		panic("internal error")
   941  	}
   942  
   943  	tok := r.read()
   944  	if tok.Rune != '(' {
   945  		p.report.ErrTok(tok, "expected '('")
   946  		return nil
   947  	}
   948  
   949  	for !r.eof(true) {
   950  		arg, more := p.parseMacroArg(r)
   951  		args = append(args, arg)
   952  		if more {
   953  			continue
   954  		}
   955  
   956  		if r.eof(true) || r.peek().Rune == ')' {
   957  			break
   958  		}
   959  	}
   960  
   961  	if r.eof(true) {
   962  		p.report.ErrTok(tok, "missing final ')'")
   963  		return nil
   964  	}
   965  
   966  	tok = r.read()
   967  	if tok.Rune != ')' {
   968  		p.report.ErrTok(tok, "expected ')'")
   969  	}
   970  
   971  	return args
   972  }
   973  
   974  func (p *pp) parseMacroArg(r tokenReader) (arg []xc.Token, more bool) {
   975  	n := 0
   976  	tok := r.peek()
   977  	for {
   978  		if r.eof(true) {
   979  			p.report.ErrTok(tok, "unexpected end of line after token")
   980  			return arg, false
   981  		}
   982  
   983  		tok = r.peek()
   984  		switch tok.Rune {
   985  		case '(':
   986  			arg = append(arg, r.read())
   987  			n++
   988  		case ')':
   989  			if n == 0 {
   990  				return arg, false
   991  			}
   992  
   993  			arg = append(arg, r.read())
   994  			n--
   995  		case ',':
   996  			if n == 0 {
   997  				arg = append(arg, r.read())
   998  				return arg, true
   999  			}
  1000  
  1001  			arg = append(arg, r.read())
  1002  		default:
  1003  			arg = append(arg, r.read())
  1004  		}
  1005  	}
  1006  }
  1007  
  1008  func (p *pp) preprocessingFile(n *PreprocessingFile) {
  1009  	ppf := p.ppf
  1010  	p.ppf = n
  1011  	p.groupList(n.GroupList)
  1012  	p.ppf = ppf
  1013  	if p.includeLevel == 0 {
  1014  		close(p.in)
  1015  		<-p.ack
  1016  	}
  1017  }
  1018  
  1019  func (p *pp) groupList(n *GroupList) {
  1020  	for ; n != nil; n = n.GroupList {
  1021  		switch gp := n.GroupPart.(type) {
  1022  		case nil: // PPNONDIRECTIVE PPTokenList
  1023  			// nop
  1024  		case *ControlLine:
  1025  			p.controlLine(gp)
  1026  		case *IfSection:
  1027  			p.ifSection(gp)
  1028  		case PPTokenList: // TextLine
  1029  			if gp == 0 {
  1030  				break
  1031  			}
  1032  
  1033  			toks := decodeTokens(gp, nil, true)
  1034  			for _, v := range toks {
  1035  				if v.Rune != ' ' {
  1036  					p.in <- toks
  1037  					<-p.ack
  1038  					break
  1039  				}
  1040  			}
  1041  		case xc.Token:
  1042  			if p.tweaks.enableWarnings {
  1043  				fmt.Printf("[INFO] %s at %s\n", gp.S(), xc.FileSet.Position(gp.Pos()).String())
  1044  			}
  1045  		default:
  1046  			panic("internal error")
  1047  		}
  1048  	}
  1049  }
  1050  
  1051  func (p *pp) ifSection(n *IfSection) {
  1052  	if p.ifGroup(n.IfGroup) || p.elifGroupListOpt(n.ElifGroupListOpt) {
  1053  		return
  1054  	}
  1055  
  1056  	p.elseGroupOpt(n.ElseGroupOpt)
  1057  }
  1058  
  1059  func (p *pp) ifGroup(n *IfGroup) bool {
  1060  	switch n.Case {
  1061  	case 0: // PPIF PPTokenList GroupListOpt
  1062  		if !p.lx.parsePPConstExpr(n.PPTokenList, p) {
  1063  			return false
  1064  		}
  1065  	case 1: // PPIFDEF IDENTIFIER '\n' GroupListOpt
  1066  		if m := p.macros.m[n.Token2.Val]; m == nil {
  1067  			return false
  1068  		}
  1069  	case 2: // PPIFNDEF IDENTIFIER '\n' GroupListOpt
  1070  		if m := p.macros.m[n.Token2.Val]; m != nil {
  1071  			return false
  1072  		}
  1073  	default:
  1074  		panic(n.Case)
  1075  	}
  1076  	p.groupListOpt(n.GroupListOpt)
  1077  	return true
  1078  }
  1079  
  1080  func (p *pp) elifGroupListOpt(n *ElifGroupListOpt) bool {
  1081  	if n == nil {
  1082  		return false
  1083  	}
  1084  
  1085  	return p.elifGroupList(n.ElifGroupList)
  1086  }
  1087  
  1088  func (p *pp) elifGroupList(n *ElifGroupList) bool {
  1089  	for ; n != nil; n = n.ElifGroupList {
  1090  		if p.elifGroup(n.ElifGroup) {
  1091  			return true
  1092  		}
  1093  	}
  1094  
  1095  	return false
  1096  }
  1097  
  1098  func (p *pp) elifGroup(n *ElifGroup) bool {
  1099  	if !p.lx.parsePPConstExpr(n.PPTokenList, p) {
  1100  		return false
  1101  	}
  1102  
  1103  	p.groupListOpt(n.GroupListOpt)
  1104  	return true
  1105  }
  1106  
  1107  func (p *pp) elseGroupOpt(n *ElseGroupOpt) {
  1108  	if n == nil {
  1109  		return
  1110  	}
  1111  
  1112  	p.groupListOpt(n.ElseGroup.GroupListOpt)
  1113  }
  1114  
  1115  func (p *pp) groupListOpt(n *GroupListOpt) {
  1116  	if n == nil {
  1117  		return
  1118  	}
  1119  
  1120  	p.groupList(n.GroupList)
  1121  }
  1122  
  1123  func (p *pp) fixInclude(toks []xc.Token) []xc.Token {
  1124  again:
  1125  	if len(toks) == 0 {
  1126  		return nil
  1127  	}
  1128  
  1129  	switch toks[0].Rune {
  1130  	case ' ':
  1131  		toks = toks[1:]
  1132  		goto again
  1133  	case STRINGLITERAL, PPHEADER_NAME:
  1134  		return toks
  1135  	case '<':
  1136  		for i := 1; i < len(toks); i++ {
  1137  			if toks[i].Rune == '>' {
  1138  				r := stringify(toks[1:i])
  1139  				return []xc.Token{r}
  1140  			}
  1141  		}
  1142  
  1143  		return nil
  1144  	default:
  1145  		return nil
  1146  	}
  1147  }
  1148  
  1149  func (p *pp) pragma1(a []xc.Token) (t xc.Token, _ bool) {
  1150  	if len(a) != 3 || a[0].Rune != '(' || a[1].Rune != STRINGLITERAL || a[2].Rune != ')' {
  1151  		return t, false
  1152  	}
  1153  
  1154  	return a[1], true
  1155  }
  1156  
  1157  func (p *pp) pragma(a []xc.Token) {
  1158  	if len(a) == 0 {
  1159  		return
  1160  	}
  1161  
  1162  	switch t := a[0]; t.Val {
  1163  	case idPushMacro:
  1164  		t, ok := p.pragma1(a[1:])
  1165  		if !ok {
  1166  			break
  1167  		}
  1168  
  1169  		s := dict.S(t.Val)
  1170  		nm := dict.ID(s[1 : len(s)-1])
  1171  		m := p.macros.m[nm]
  1172  		if m == nil {
  1173  			break
  1174  		}
  1175  
  1176  		p.macros.stack[nm] = append(p.macros.stack[nm], m)
  1177  	case idPopMacro:
  1178  		t, ok := p.pragma1(a[1:])
  1179  		if !ok {
  1180  			break
  1181  		}
  1182  
  1183  		s := dict.S(t.Val)
  1184  		nm := dict.ID(s[1 : len(s)-1])
  1185  		stack := p.macros.stack[nm]
  1186  		if len(stack) == 0 {
  1187  			break
  1188  		}
  1189  
  1190  		m := stack[0]
  1191  		p.macros.stack[nm] = stack[1:]
  1192  		p.macros.m[nm] = m
  1193  	}
  1194  }
  1195  
  1196  func (p *pp) controlLine(n *ControlLine) {
  1197  out:
  1198  	switch n.Case {
  1199  	case 0: // PPDEFINE IDENTIFIER ReplacementList
  1200  		p.defineMacro(n.Token2, n.ReplacementList)
  1201  	case 1: // PPDEFINE IDENTIFIER_LPAREN "..." ')' ReplacementList
  1202  		p.defineFnMacro(n.Token2, nil, n.ReplacementList, true, false)
  1203  	case 2: // PPDEFINE IDENTIFIER_LPAREN IdentifierList ',' "..." ')' ReplacementList
  1204  		p.defineFnMacro(n.Token2, n.IdentifierList, n.ReplacementList, true, false)
  1205  	case 3: // PPDEFINE IDENTIFIER_LPAREN IdentifierListOpt ')' ReplacementList
  1206  		var l *IdentifierList
  1207  		if o := n.IdentifierListOpt; o != nil {
  1208  			l = o.IdentifierList
  1209  		}
  1210  		p.defineFnMacro(n.Token2, l, n.ReplacementList, false, false)
  1211  	case 5: // PPHASH_NL
  1212  		// nop
  1213  	case 4: // PPERROR PPTokenListOpt
  1214  		var sep string
  1215  		toks := decodeTokens(n.PPTokenListOpt, nil, true)
  1216  		s := stringify(toks)
  1217  		if s.Val != 0 {
  1218  			sep = ": "
  1219  		}
  1220  		p.report.ErrTok(n.Token, "error%s%s", sep, s.S())
  1221  	case 6: // PPINCLUDE PPTokenList
  1222  		toks := decodeTokens(n.PPTokenList, nil, false)
  1223  		var exp []xc.Token
  1224  		p.expand(&tokenBuf{toks}, false, func(toks []xc.Token) { exp = append(exp, toks...) })
  1225  		toks = p.fixInclude(exp)
  1226  		if len(toks) == 0 {
  1227  			p.report.ErrTok(n.Token, "invalid #include argument")
  1228  			break
  1229  		}
  1230  
  1231  		if p.includeLevel == maxIncludeLevel {
  1232  			p.report.ErrTok(toks[0], "too many include nesting levels")
  1233  			break
  1234  		}
  1235  
  1236  		currentFileDir := filepath.Dir(p.ppf.path)
  1237  		arg := string(toks[0].S())
  1238  		var dirs []string
  1239  		switch {
  1240  		case strings.HasPrefix(arg, "<"):
  1241  			switch {
  1242  			case p.tweaks.mode99c:
  1243  				dirs = append([]string(nil), p.sysIncludes...)
  1244  			default:
  1245  				dirs = append(p.includes, p.sysIncludes...)
  1246  			}
  1247  		case strings.HasPrefix(arg, "\""):
  1248  			switch {
  1249  			case p.tweaks.mode99c:
  1250  				dirs = append([]string(nil), p.includes...)
  1251  			default:
  1252  				dirs = p.includes
  1253  				dirs = append([]string{filepath.Dir(p.ppf.path)}, dirs...)
  1254  			}
  1255  		default:
  1256  			p.report.ErrTok(n.Token, "invalid #include argument")
  1257  			break out
  1258  		}
  1259  
  1260  		// Include origin.
  1261  		arg = arg[1 : len(arg)-1]
  1262  		for i, dir := range dirs {
  1263  			if p.tweaks.mode99c && dir == "@" {
  1264  				dir = currentFileDir
  1265  				dirs[i] = dir
  1266  			}
  1267  			pth := arg
  1268  			if !filepath.IsAbs(pth) {
  1269  				pth = filepath.Join(dir, arg)
  1270  			}
  1271  			if _, err := os.Stat(pth); err != nil {
  1272  				if !os.IsNotExist(err) {
  1273  					p.report.ErrTok(toks[0], err.Error())
  1274  				}
  1275  				if debugIncludes {
  1276  					fmt.Fprintf(os.Stderr, "include file %q not found\n", pth)
  1277  				}
  1278  				continue
  1279  			}
  1280  
  1281  			ppf, err := ppParse(pth, p.report, p.tweaks)
  1282  			if err != nil {
  1283  				p.report.ErrTok(toks[0], err.Error())
  1284  				return
  1285  			}
  1286  
  1287  			p.includeLevel++
  1288  			save := p.includedSearchPath
  1289  			p.includedSearchPath = dir
  1290  			p.preprocessingFile(ppf)
  1291  			p.includedSearchPath = save
  1292  			p.includeLevel--
  1293  			return
  1294  		}
  1295  
  1296  		p.report.ErrTok(toks[0], "include file not found: %s. Search paths:\n\t%s", arg, strings.Join(clean(dirs), "\n\t"))
  1297  	case 7: // PPLINE PPTokenList '\n'
  1298  		toks := decodeTokens(n.PPTokenList, nil, false)
  1299  		// lineno, fname
  1300  		if len(toks) < 2 || toks[0].Rune != INTCONST || toks[1].Rune != STRINGLITERAL {
  1301  			break
  1302  		}
  1303  
  1304  		ln, err := strconv.ParseUint(string(toks[0].S()), 10, mathutil.IntBits-1)
  1305  		if err != nil {
  1306  			break
  1307  		}
  1308  
  1309  		fn := string(toks[1].S())
  1310  		fn = fn[1 : len(fn)-1] // Unquote.
  1311  		nl := n.Token2
  1312  		tf := xc.FileSet.File(nl.Pos())
  1313  		tf.AddLineInfo(tf.Offset(nl.Pos()+1), fn, int(ln))
  1314  	case 8: // PPPRAGMA PPTokenListOpt
  1315  		p.pragma(decodeTokens(n.PPTokenListOpt, nil, false))
  1316  	case
  1317  		9,  // PPUNDEF IDENTIFIER '\n'
  1318  		12: // PPUNDEF IDENTIFIER PPTokenList '\n'
  1319  		nm := n.Token2.Val
  1320  		if protectedMacros[nm] && p.protectMacros {
  1321  			p.report.ErrTok(n.Token2, "cannot undefine protected macro")
  1322  			return
  1323  		}
  1324  
  1325  		if debugMacros {
  1326  			fmt.Fprintf(os.Stderr, "#undef %s\n", xc.Dict.S(nm))
  1327  		}
  1328  		delete(p.macros.m, nm)
  1329  	case 10: // PPDEFINE IDENTIFIER_LPAREN IdentifierList "..." ')' ReplacementList
  1330  		p.defineFnMacro(n.Token2, n.IdentifierList, n.ReplacementList, false, true)
  1331  	case 13: // PPINCLUDE_NEXT PPTokenList '\n'
  1332  		toks := decodeTokens(n.PPTokenList, nil, false)
  1333  		var exp []xc.Token
  1334  		p.expand(&tokenBuf{toks}, false, func(toks []xc.Token) { exp = append(exp, toks...) })
  1335  		toks = p.fixInclude(exp)
  1336  		if len(toks) == 0 {
  1337  			p.report.ErrTok(n.Token, "invalid #include_next argument")
  1338  			break
  1339  		}
  1340  
  1341  		if p.includeLevel == maxIncludeLevel {
  1342  			p.report.ErrTok(toks[0], "too many include nesting levels")
  1343  			break
  1344  		}
  1345  
  1346  		arg := string(toks[0].S())
  1347  		arg = arg[1 : len(arg)-1]
  1348  		origin := p.includedSearchPath
  1349  		var dirs []string
  1350  		found := false
  1351  		for i, dir := range p.includes {
  1352  			if dir == origin {
  1353  				dirs = p.includes[i+1:]
  1354  				found = true
  1355  				break
  1356  			}
  1357  		}
  1358  		if !found {
  1359  			for i, dir := range p.sysIncludes {
  1360  				if dir == origin {
  1361  					dirs = p.sysIncludes[i+1:]
  1362  					found = true
  1363  					break
  1364  				}
  1365  			}
  1366  		}
  1367  
  1368  		for _, dir := range dirs {
  1369  			pth := filepath.Join(dir, arg)
  1370  			if _, err := os.Stat(pth); err != nil {
  1371  				if !os.IsNotExist(err) {
  1372  					p.report.ErrTok(toks[0], err.Error())
  1373  				}
  1374  				if debugIncludes {
  1375  					fmt.Fprintf(os.Stderr, "include file %q not found\n", pth)
  1376  				}
  1377  				continue
  1378  			}
  1379  
  1380  			ppf, err := ppParse(pth, p.report, p.tweaks)
  1381  			if err != nil {
  1382  				p.report.ErrTok(toks[0], err.Error())
  1383  				return
  1384  			}
  1385  
  1386  			p.includeLevel++
  1387  			save := p.includedSearchPath
  1388  			p.includedSearchPath = dir
  1389  			p.preprocessingFile(ppf)
  1390  			p.includedSearchPath = save
  1391  			p.includeLevel--
  1392  			return
  1393  		}
  1394  
  1395  		p.report.ErrTok(toks[0], "include file not found: %s", arg)
  1396  	default:
  1397  		panic(n.Case)
  1398  	}
  1399  }