modernc.org/gocc@v0.0.1/main.go (about)

     1  // Copyright 2019 The GOCC 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 main // import "modernc.org/gocc"
     6  
     7  //TODO https://todo.sr.ht/~mcf/cc-issues/52
     8  //TODO https://todo.sr.ht/~mcf/cc-issues/56
     9  //TODO cdecl
    10  
    11  import (
    12  	"bufio"
    13  	"fmt"
    14  	"io"
    15  	"io/ioutil"
    16  	"os"
    17  	"path/filepath"
    18  	"runtime"
    19  	"runtime/debug"
    20  	"strings"
    21  	"sync"
    22  	"unsafe"
    23  
    24  	"modernc.org/cc/v3"
    25  	"modernc.org/fileutil"
    26  	"modernc.org/opt"
    27  	qbec "modernc.org/qbe"
    28  )
    29  
    30  const (
    31  	version = "0.1.0 pre-alpha"
    32  
    33  	builtin = `
    34  #define __DI__
    35  #define __FUNCTION__ __func__
    36  #define __HI__
    37  #define __PRETTY_FUNCTION__ __func__
    38  #define __QI__
    39  #define __SI__
    40  #define __builtin_abort abort
    41  #define __builtin_abs abs
    42  #define __builtin_alloca alloca
    43  #define __builtin_bcopy bcopy
    44  #define __builtin_cimag cimag
    45  #define __builtin_cimagf cimagf
    46  #define __builtin_cimagl cimagl
    47  #define __builtin_conj conj
    48  #define __builtin_conjf conjf
    49  #define __builtin_conjl conjl
    50  #define __builtin_constant_p(x) __builtin_constant_p_impl(0, x)
    51  #define __builtin_copysign copysign
    52  #define __builtin_copysignf copysignf
    53  #define __builtin_creal creal
    54  #define __builtin_crealf crealf
    55  #define __builtin_creall creall
    56  #define __builtin_expect(exp, c) exp
    57  #define __builtin_fabs fabs
    58  #define __builtin_ffs ffs
    59  #define __builtin_fprintf fprintf
    60  #define __builtin_fprintf_unlocked fprintf
    61  #define __builtin_fputc fputc
    62  #define __builtin_fputs fputs
    63  #define __builtin_fputs_unlocked fputs
    64  #define __builtin_free free
    65  #define __builtin_fwrite fwrite
    66  #define __builtin_index index
    67  #define __builtin_labs labs
    68  #define __builtin_llabs llabs
    69  #define __builtin_malloc malloc
    70  #define __builtin_memchr memchr
    71  #define __builtin_memcmp memcmp
    72  #define __builtin_memcpy memcpy
    73  #define __builtin_memmove memmove
    74  #define __builtin_mempcpy memcpy
    75  #define __builtin_memset memset
    76  #define __builtin_offsetof(type, member) ((__SIZE_TYPE__)&(((type*)0)->member))
    77  #define __builtin_prefetch(...) (void)(__VA_ARGS__)
    78  #define __builtin_printf printf
    79  #define __builtin_printf_unlocked printf
    80  #define __builtin_putchar putchar
    81  #define __builtin_puts puts
    82  #define __builtin_snprintf snprintf
    83  #define __builtin_sprintf sprintf
    84  #define __builtin_strcat strcat
    85  #define __builtin_strchr strchr
    86  #define __builtin_strcmp strcmp
    87  #define __builtin_strcpy strcpy
    88  #define __builtin_strlen strlen
    89  #define __builtin_strncat strncat
    90  #define __builtin_strncmp strncmp
    91  #define __builtin_trap abort
    92  #define __builtin_unreachable abort
    93  #define __builtin_va_arg(ap, type) (type)__gocc_va_arg(ap)
    94  #define __builtin_va_copy(dst, src) dst = src
    95  #define __builtin_va_end(ap) __gocc_va_end(ap)
    96  #define __builtin_va_start(ap, v) __gocc_va_start(ap)
    97  #define __declspec(...)
    98  #define __extension__
    99  #define __signed__ signed
   100  #define __sync_synchronize(...)
   101  #define __word__
   102  #define asm __asm__
   103  #define fputs_unlocked fputs
   104  
   105  #if __SIZEOF_POINTER__ == 8
   106  typedef void* __builtin_va_list[3];
   107  #else
   108  typedef void* __builtin_va_list[1];
   109  typedef long double __float128;
   110  #endif
   111  
   112  #ifndef __GNUC__
   113  #define __attribute(x)
   114  #define __attribute__(x)
   115  #define alloca(size)   __gocc_alloca (size)
   116  #endif
   117  
   118  
   119  #ifdef __PTRDIFF_TYPE__
   120  typedef __PTRDIFF_TYPE__ ptrdiff_t;
   121  #endif
   122  
   123  #ifdef __SIZE_TYPE__
   124  typedef __SIZE_TYPE__ size_t;
   125  #endif
   126  
   127  #ifdef __WCHAR_TYPE__
   128  typedef __WCHAR_TYPE__ wchar_t;
   129  #endif
   130  
   131  #ifdef __UINT16_TYPE__
   132  __UINT16_TYPE__ __builtin_bswap16 (__UINT16_TYPE__ x);
   133  #endif
   134  
   135  #ifdef __UINT32_TYPE__
   136  __UINT32_TYPE__ __builtin_bswap32 (__UINT32_TYPE__ x);
   137  #endif
   138  
   139  #ifdef __UINT64_TYPE__
   140  __UINT64_TYPE__ __builtin_bswap64 (__UINT64_TYPE__ x);
   141  #endif
   142  
   143  #if __SIZEOF_POINTER__ == 4 && !defined(__ILP32__)
   144  #define __ILP32__ 1
   145  #endif
   146  
   147  typedef struct { char real, imag; } __COMPLEX_CHAR_TYPE__;
   148  typedef struct { double real, imag; } __COMPLEX_DOUBLE_TYPE__;
   149  typedef struct { float real, imag; } __COMPLEX_FLOAT_TYPE__;
   150  typedef struct { int real, imag; } __COMPLEX_INT_TYPE__;
   151  typedef struct { long double real, imag; } __COMPLEX_LONG_DOUBLE_TYPE__;
   152  typedef struct { long real, imag; } __COMPLEX_LONG_TYPE__;
   153  typedef struct { long long real, imag; } __COMPLEX_LONG_LONG_TYPE__;
   154  typedef struct { long long unsigned real, imag; } __COMPLEX_LONG_LONG_UNSIGNED_TYPE__;
   155  typedef struct { long unsigned real, imag; } __COMPLEX_LONG_UNSIGNED_TYPE__;
   156  typedef struct { short real, imag; } __COMPLEX_SHORT_TYPE__;
   157  typedef struct { unsigned real, imag; } __COMPLEX_UNSIGNED_TYPE__;
   158  typedef struct { unsigned short real, imag; } __COMPLEX_SHORT_UNSIGNED_TYPE__;
   159  
   160  int __builtin_clzll (unsigned long long); //TODO-
   161  int __builtin_constant_p_impl(int, ...);
   162  int __printf__ ( const char * format, ... ); //TODO-
   163  int __scanf__ ( const char *format, ... ); //TODO-
   164  void *__gocc_alloca(size_t size);
   165  void *__gocc_va_arg(void* ap);
   166  void *__gocc_va_end(void* ap);
   167  void *__gocc_va_start(void* ap);
   168  `
   169  )
   170  
   171  var (
   172  	_ = ioutil.ReadFile
   173  
   174  	arch              = 8 * unsafe.Sizeof(uintptr(0))
   175  	hostConfigOnce32  sync.Once
   176  	hostConfigOnce64  sync.Once
   177  	hostPredef32      string
   178  	hostIncludes32    []string
   179  	hostSysIncludes32 []string
   180  	hostPredef64      string
   181  	hostIncludes64    []string
   182  	hostSysIncludes64 []string
   183  
   184  	isTesting bool
   185  	traceIL   bool
   186  )
   187  
   188  func hostConfig(opts ...string) (hostPredef string, hostIncludes, hostSysIncludes []string, err error) {
   189  	hostPredef, hostIncludes, hostSysIncludes, err = cc.HostConfig("", opts...)
   190  	if err != nil {
   191  		return "", nil, nil, err
   192  	}
   193  
   194  	a := strings.Split(hostPredef, "\n")
   195  	w := 0
   196  	for _, v0 := range a {
   197  		v := strings.TrimSpace(strings.ToLower(v0))
   198  		if !strings.HasPrefix(v, "#define __gnu") && !strings.HasPrefix(v, "#define __gcc") {
   199  			a[w] = v0
   200  			w++
   201  		}
   202  	}
   203  	hostPredef = strings.Join(a[:w], "\n")
   204  	return hostPredef, hostIncludes, hostSysIncludes, err
   205  }
   206  
   207  func internalError() int                               { return internalErrorf("") }
   208  func internalErrorf(s string, args ...interface{}) int { panic(fmt.Errorf(s, args...)) }
   209  
   210  type task struct {
   211  	args []string
   212  	ast  *cc.AST
   213  	cc.Config
   214  	includePaths    []string
   215  	inputs          []int
   216  	intType         cc.Type
   217  	predefined      string
   218  	ptrType         cc.Type
   219  	qbeArgs         []string
   220  	stderr          io.Writer
   221  	stdout          io.Writer
   222  	sysIncludePaths []string
   223  	temps           []string
   224  	testSources     []cc.Source // testing //TODO-
   225  	wr              io.Writer
   226  
   227  	opts struct {
   228  		D                []string                 // -D
   229  		I                []string                 // -I
   230  		U                []string                 // -U
   231  		o                string                   // -o
   232  		qbecPkgName      string                   // -qbec-pkgname
   233  		qbecStaticPrefix string                   // -qbec-static-prefix
   234  		qbecVolatile     map[cc.StringID]struct{} // -qbec-volatile
   235  		rpath            string                   // -rpath
   236  		soname           string                   // -soname
   237  		std              string                   // -std
   238  
   239  		C                        bool // -C
   240  		E                        bool // -E
   241  		c                        bool // -c
   242  		fPIC                     bool // -fPIC
   243  		fpic                     bool // -fpic
   244  		goccAllocatedDeclarators bool // -gocc-allocated-declarators
   245  		goccEmitDefintions       bool // -gocc-emit-definitions
   246  		goccPedantic             bool // -gocc-pedantic
   247  		goccTrc                  bool
   248  		m32                      bool // -m32
   249  		m64                      bool // -m64
   250  		noWholeArchive           bool // --no-whole-archive
   251  		shared                   bool // -shared
   252  		wholeArchive             bool // --whole-archive
   253  	}
   254  
   255  	doNotCache     bool
   256  	doNotCacheMain bool
   257  	genQBE         bool // -o foo.qbe
   258  }
   259  
   260  var (
   261  	accept = []string{".c", ".h"}
   262  )
   263  
   264  // args are like os.Args, len always > 0.
   265  func newTask(args []string) (t *task, err error) {
   266  	if dmesgs {
   267  		dmesg("newTask %q", args)
   268  	}
   269  	wd, err := os.Getwd()
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  
   274  	t = &task{
   275  		args: args,
   276  	}
   277  	t.Config.PragmaHandler = t.pragmaHandler
   278  	t.Config.WorkingDir = wd
   279  
   280  	p := opt.NewSet()
   281  	p.Opt("C", func(opt string) error { t.opts.C = true; return nil })
   282  	p.Opt("E", func(opt string) error { t.opts.E = true; return nil })
   283  	p.Opt("c", func(opt string) error { t.opts.c = true; t.qbeArgs = append(t.qbeArgs, opt); return nil })
   284  	p.Opt("fPIC", func(opt string) error { t.opts.fPIC = true; t.qbeArgs = append(t.qbeArgs, opt); return nil })
   285  	p.Opt("fpic", func(opt string) error { t.opts.fpic = true; t.qbeArgs = append(t.qbeArgs, opt); return nil })
   286  	p.Opt("m32", func(opt string) error { t.opts.m32 = true; t.qbeArgs = append(t.qbeArgs, opt); return nil })
   287  	p.Opt("m64", func(opt string) error { t.opts.m64 = true; t.qbeArgs = append(t.qbeArgs, opt); return nil })
   288  	p.Opt("shared", func(opt string) error { t.opts.shared = true; t.qbeArgs = append(t.qbeArgs, opt); return nil })
   289  	p.Arg("D", true, func(opt, arg string) error {
   290  		t.opts.D = append(t.opts.D, arg)
   291  		t.qbeArgs = append(t.qbeArgs, opt+arg) //TODO-?
   292  		return nil
   293  	})
   294  	p.Arg("qbec-crt", false, func(opt, arg string) error {
   295  		t.qbeArgs = append(t.qbeArgs, opt, arg)
   296  		return nil
   297  	})
   298  	p.Arg("qbec-import", false, func(opt, arg string) error {
   299  		t.qbeArgs = append(t.qbeArgs, opt, arg)
   300  		return nil
   301  	})
   302  	p.Arg("qbec-dot-import", false, func(opt, arg string) error {
   303  		t.qbeArgs = append(t.qbeArgs, opt, arg)
   304  		return nil
   305  	})
   306  	p.Arg("qbec-pkgname", false, func(opt, arg string) error {
   307  		t.opts.qbecPkgName = arg //TODO-
   308  		t.qbeArgs = append(t.qbeArgs, opt, arg)
   309  		return nil
   310  	})
   311  	p.Arg("qbec-static-prefix", false, func(opt, arg string) error {
   312  		t.opts.qbecStaticPrefix = arg //TODO-
   313  		t.qbeArgs = append(t.qbeArgs, opt, arg)
   314  		return nil
   315  	})
   316  	p.Arg("qbec-volatile", false, func(opt, arg string) error {
   317  		a := strings.Split(arg, ",")
   318  		if t.opts.qbecVolatile == nil {
   319  			t.opts.qbecVolatile = map[cc.StringID]struct{}{}
   320  		}
   321  		for _, v := range a {
   322  			t.opts.qbecVolatile[cc.String(strings.TrimSpace(v))] = struct{}{}
   323  		}
   324  		return nil
   325  	})
   326  	p.Arg("I", true, func(opt, arg string) error { t.opts.I = append(t.opts.I, arg); return nil })
   327  	p.Arg("U", true, func(opt, arg string) error {
   328  		t.opts.U = append(t.opts.U, arg)
   329  		t.qbeArgs = append(t.qbeArgs, opt+arg) //TODO-?
   330  		return nil
   331  	})
   332  	p.Arg("o", false, func(opt, arg string) error {
   333  		if t.opts.o != "" {
   334  			return fmt.Errorf("multiple -o options present")
   335  		}
   336  
   337  		t.opts.o = arg
   338  		switch filepath.Ext(arg) {
   339  		case ".qbe":
   340  			t.genQBE = true
   341  		default:
   342  			t.qbeArgs = append(t.qbeArgs, opt, arg)
   343  		}
   344  		return nil
   345  	})
   346  	p.Arg("rpath", false, func(opt, arg string) error {
   347  		t.opts.rpath = arg
   348  		t.qbeArgs = append(t.qbeArgs, "-Wl,-rpath", fmt.Sprintf("-Wl,%s", arg))
   349  		return nil
   350  	})
   351  	p.Arg("std", false, func(opt, arg string) error {
   352  		t.opts.std = arg
   353  		t.qbeArgs = append(t.qbeArgs, fmt.Sprintf("-std=%v", arg))
   354  		return nil
   355  	})
   356  	p.Arg("soname", false, func(opt, arg string) error {
   357  		t.opts.soname = arg
   358  		t.qbeArgs = append(t.qbeArgs, "-Wl,-soname", fmt.Sprintf("-Wl,%s", arg))
   359  		return nil
   360  	})
   361  	p.Opt("-whole-archive", func(opt string) error {
   362  		t.opts.wholeArchive = true
   363  		t.qbeArgs = append(t.qbeArgs, "-Wl,--whole-archive")
   364  		return nil
   365  	})
   366  	p.Opt("-no-whole-archive", func(opt string) error {
   367  		t.opts.noWholeArchive = true
   368  		t.qbeArgs = append(t.qbeArgs, "-Wl,--no-whole-archive")
   369  		return nil
   370  	})
   371  	p.Opt("gocc-long-double-is-double", func(opt string) error { t.Config.LongDoubleIsDouble = true; return nil })
   372  	p.Opt("gocc-emit-definitions", func(opt string) error { t.opts.goccEmitDefintions = true; return nil })
   373  	p.Opt("gocc-pedantic", func(opt string) error { t.opts.goccPedantic = true; return nil })
   374  	p.Opt("gocc-allocated-declarators", func(opt string) error { t.opts.goccAllocatedDeclarators = true; return nil })
   375  	p.Opt("gocc-trc", func(opt string) error { t.opts.goccTrc = true; return nil })
   376  	if err := p.Parse(args[1:], func(name string) error {
   377  		t.qbeArgs = append(t.qbeArgs, name)
   378  		if strings.HasPrefix(name, "-") {
   379  			return nil
   380  		}
   381  
   382  		ext := filepath.Ext(name)
   383  		for _, a := range accept {
   384  			if ext == a {
   385  				t.inputs = append(t.inputs, len(t.qbeArgs)-1)
   386  				return nil
   387  			}
   388  		}
   389  
   390  		return nil
   391  	}); err != nil {
   392  		return nil, err
   393  	}
   394  
   395  	if t.opts.c && t.opts.o == "" && len(t.inputs) != 0 {
   396  		base := filepath.Base(t.qbeArgs[t.inputs[0]])
   397  		ext := filepath.Ext(base)
   398  		base = base[:len(base)-len(ext)]
   399  		base += ".o"
   400  		t.qbeArgs = append(t.qbeArgs, "-o", base)
   401  	}
   402  
   403  	if s := t.opts.o; filepath.Ext(s) == ".go" && t.opts.qbecPkgName == "" && t.opts.qbecStaticPrefix == "" {
   404  		s = filepath.Base(s)
   405  		s = s[:len(s)-len(".go")]
   406  		s = strings.ReplaceAll(s, "-", "")
   407  		s = strings.ReplaceAll(s, ".", "")
   408  		s = strings.ReplaceAll(s, "_", "")
   409  		if !strings.HasPrefix(s, "s") {
   410  			s = "s" + s
   411  		}
   412  		t.qbeArgs = append(t.qbeArgs, "-qbec-static-prefix", s+"_")
   413  	}
   414  
   415  	return t, nil
   416  }
   417  
   418  func (t *task) pragmaHandler(p cc.Pragma, toks []cc.Token) {
   419  	if len(toks) == 0 {
   420  		return
   421  	}
   422  	switch s := toks[0].Value.String(); s {
   423  	case "push_macro", "pop_macro":
   424  		toks = toks[1:]
   425  		if len(toks) == 3 && toks[0].Rune == '(' && toks[1].Rune == cc.STRINGLITERAL && toks[2].Rune == ')' {
   426  			nm := toks[1].String()
   427  			if len(nm) < 3 {
   428  				todo(nil) //TODO report error
   429  			}
   430  			nm = nm[1 : len(nm)-1]
   431  			switch s {
   432  			case "push_macro":
   433  				p.PushMacro(nm)
   434  			case "pop_macro":
   435  				p.PopMacro(nm)
   436  			default:
   437  				panic("internal error") //TODOOK
   438  			}
   439  			break
   440  		}
   441  
   442  		todo(nil) //TODO report error
   443  	}
   444  }
   445  
   446  func (t *task) w(s string, args ...interface{}) {
   447  	//fmt.Printf(s, args...) //TODO-
   448  	if _, err := fmt.Fprintf(t.wr, s, args...); err != nil {
   449  		panic(err) // Handled in main
   450  	}
   451  }
   452  
   453  // The "real" main, possibly executed by the server process, if available, ie.
   454  // in a different process than main is executing in.
   455  func (t *task) main(stdout, stderr io.Writer) (exitCode int) {
   456  	if dmesgs {
   457  		dmesg("main entered: %v", os.Args)
   458  
   459  		defer func() {
   460  			dmesg("main exiting: %v", exitCode)
   461  		}()
   462  	}
   463  	t.stdout = stdout
   464  	t.stderr = stderr
   465  
   466  	var hostPredef string
   467  	var hostIncludes, hostSysIncludes []string
   468  	var err error
   469  	switch {
   470  	case t.opts.m32 && arch != 32:
   471  		hostConfigOnce32.Do(func() { hostPredef32, hostIncludes32, hostSysIncludes32, err = hostConfig("-m32") })
   472  		hostPredef = hostPredef32
   473  		hostIncludes = hostIncludes32
   474  		hostSysIncludes = hostSysIncludes32
   475  	case t.opts.m64 && arch != 64:
   476  		hostConfigOnce32.Do(func() { hostPredef64, hostIncludes64, hostSysIncludes64, err = hostConfig("-m64") })
   477  		hostPredef = hostPredef64
   478  		hostIncludes = hostIncludes64
   479  		hostSysIncludes = hostSysIncludes64
   480  	default:
   481  		hostConfigOnce64.Do(func() { hostPredef64, hostIncludes64, hostSysIncludes64, err = hostConfig() })
   482  		hostPredef = hostPredef64
   483  		hostIncludes = hostIncludes64
   484  		hostSysIncludes = hostSysIncludes64
   485  	}
   486  	if err != nil {
   487  		fmt.Fprintln(stderr, err)
   488  		return 1
   489  	}
   490  
   491  	// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html
   492  	//
   493  	// Headers whose names are enclosed in double-quotes ( "" ) shall be
   494  	// searched for first in the directory of the file with the #include
   495  	// line, then in directories named in -I options, and last in the usual
   496  	// places
   497  	t.includePaths = append([]string{"@"}, t.opts.I...)
   498  	t.includePaths = append(t.includePaths, hostIncludes...)
   499  	t.includePaths = append(t.includePaths, hostSysIncludes...)
   500  	t.includePaths = append(t.includePaths, filepath.FromSlash("/usr/include")) //TODO nix only
   501  	// For headers whose names are enclosed in angle brackets ( "<>" ), the
   502  	// header shall be searched for only in directories named in -I options
   503  	// and then in the usual places.
   504  	t.sysIncludePaths = append(t.opts.I, hostSysIncludes...)
   505  
   506  	// if dmesgs {
   507  	// 	dmesg("includePaths:\n%v", strings.Join(t.includePaths, "\n"))
   508  	// 	dmesg("sysIncludePaths:\n%v", strings.Join(t.sysIncludePaths, "\n"))
   509  	// }
   510  
   511  	t.predefined = hostPredef
   512  	arch := runtime.GOARCH
   513  	switch {
   514  	case t.opts.m32:
   515  		switch arch {
   516  		case "386":
   517  			// nop
   518  		case "amd64":
   519  			arch = "386"
   520  		default:
   521  			fmt.Fprintf(stderr, "-m32 not supported on arch %s", arch)
   522  			return 1
   523  		}
   524  	}
   525  
   526  	t.Config.ABI, err = cc.NewABI(runtime.GOOS, arch)
   527  	if err != nil {
   528  		fmt.Fprintln(stderr, err)
   529  		return 1
   530  	}
   531  
   532  	var sources []cc.Source
   533  	if t.predefined != "" {
   534  		sources = append(sources, cc.Source{Name: "<predefined>", Value: t.predefined})
   535  	}
   536  	sources = append(sources, cc.Source{Name: "<built-in>", Value: builtin})
   537  	sources = append(sources, t.testSources...)
   538  
   539  	if len(t.opts.D) != 0 {
   540  		var a []string
   541  		for _, v := range t.opts.D {
   542  			if i := strings.IndexByte(v, '='); i > 0 {
   543  				a = append(a, fmt.Sprintf("#define %s %s", v[:i], v[i+1:]))
   544  				continue
   545  			}
   546  
   547  			a = append(a, fmt.Sprintf("#define %s 1", v))
   548  		}
   549  		a = append(a, "\n")
   550  		sources = append(sources, cc.Source{Name: "<defines>", Value: strings.Join(a, "\n")})
   551  	}
   552  
   553  	if len(t.opts.U) != 0 {
   554  		var a []string
   555  		for _, v := range t.opts.U {
   556  			a = append(a, fmt.Sprintf("#undef %s", v))
   557  		}
   558  		a = append(a, "\n")
   559  		sources = append(sources, cc.Source{Name: "<undefines>", Value: strings.Join(a, "\n")})
   560  	}
   561  
   562  	if t.opts.E {
   563  		t.Config.PreprocessOnly = true
   564  		if t.opts.C {
   565  			t.Config.PreserveWhiteSpace = true
   566  		}
   567  		for _, i := range t.inputs {
   568  			sources = append(sources, cc.Source{Name: t.qbeArgs[i]})
   569  		}
   570  		w := bufio.NewWriter(stdout)
   571  
   572  		defer w.Flush()
   573  
   574  		if err := cc.Preprocess(&t.Config, t.includePaths, t.sysIncludePaths, sources, w); err != nil {
   575  			fmt.Fprintln(t.stdout, err)
   576  			return 1
   577  		}
   578  
   579  		return 0
   580  	}
   581  
   582  	defer func() {
   583  		for _, v := range t.temps {
   584  			os.Remove(v)
   585  		}
   586  	}()
   587  
   588  	var f *os.File
   589  	var w *bufio.Writer
   590  	for _, i := range t.inputs {
   591  		nm := t.qbeArgs[i]
   592  		switch {
   593  		case t.genQBE:
   594  			if w == nil {
   595  				var err error
   596  				if f, err = os.Create(t.opts.o); err != nil {
   597  					fmt.Fprintln(stderr, err)
   598  					return 1
   599  				}
   600  
   601  				w = bufio.NewWriter(f)
   602  
   603  				defer func() {
   604  					if err := w.Flush(); err != nil {
   605  						fmt.Fprintln(stderr, err)
   606  						exitCode = 1
   607  					}
   608  					if err := f.Close(); err != nil {
   609  						fmt.Fprintln(stderr, err)
   610  						exitCode = 1
   611  					}
   612  				}()
   613  			}
   614  
   615  			if err := t.compile1(sources, nm, w); err != nil {
   616  				fmt.Fprintln(stderr, err)
   617  				return 1
   618  			}
   619  		default:
   620  			temp, err := fileutil.TempFile("", "gocc-", ".qbe")
   621  			if err != nil {
   622  				fmt.Fprintf(stderr, "cannot create temp file: %v\n", err)
   623  				return 1
   624  			}
   625  
   626  			t.temps = append(t.temps, temp.Name())
   627  			w := bufio.NewWriter(temp)
   628  
   629  			if err := t.compile1(sources, nm, w); err != nil {
   630  				fmt.Fprintln(stderr, err)
   631  				return 1
   632  			}
   633  
   634  			t.qbeArgs[i] = temp.Name()
   635  			if err := w.Flush(); err != nil {
   636  				fmt.Fprintln(stderr, err)
   637  				return 1
   638  			}
   639  
   640  			if err := temp.Close(); err != nil {
   641  				fmt.Fprintln(stderr, err)
   642  				return 1
   643  			}
   644  		}
   645  	}
   646  	if t.genQBE {
   647  		return 0
   648  	}
   649  
   650  	return qbec.Compile(append([]string{"qbec"}, t.qbeArgs...), t.stdout, t.stderr, nil)
   651  }
   652  
   653  func (t *task) compile1(sources []cc.Source, fn string, w io.Writer) (err error) {
   654  	doNotCache := t.doNotCacheMain && filepath.Base(fn) == "main.c" || t.doNotCache
   655  	sources = append(sources, cc.Source{Name: fn, DoNotCache: doNotCache})
   656  	if t.opts.goccPedantic {
   657  		t.Config.RejectCaseRange = true
   658  		t.Config.RejectElseExtraTokens = true
   659  		t.Config.RejectEmptyCompositeLiterals = true
   660  		t.Config.RejectEmptyDeclarations = true
   661  		t.Config.RejectEmptyInitializerList = true
   662  		t.Config.RejectEmptyStructs = true
   663  		t.Config.RejectEndifExtraTokens = true
   664  		t.Config.RejectFinalBackslash = true
   665  		t.Config.RejectIfdefExtraTokens = true
   666  		t.Config.RejectIfndefExtraTokens = true
   667  		t.Config.RejectInvalidVariadicMacros = true
   668  		t.Config.RejectLabelValues = true
   669  		t.Config.RejectLateBinding = true
   670  		t.Config.RejectLineExtraTokens = true
   671  		t.Config.RejectMissingConditionalExpr = true
   672  		t.Config.RejectMissingDeclarationSpecifiers = true
   673  		t.Config.RejectMissingFinalNewline = true
   674  		t.Config.RejectMissingFinalStructFieldSemicolon = true
   675  		t.Config.RejectNestedFunctionDefinitions = true
   676  		t.Config.RejectParamSemicolon = true
   677  		t.Config.RejectStatementExpressions = true
   678  		t.Config.RejectTypeof = true
   679  		t.Config.RejectUndefExtraTokens = true
   680  	}
   681  	if t.opts.goccTrc {
   682  		t.Config.InjectTracingCode = true
   683  	}
   684  	if t.ast, err = cc.Translate(&t.Config, t.includePaths, t.sysIncludePaths, sources); err != nil {
   685  		return err
   686  	}
   687  
   688  	t.intType = t.Config.ABI.Type(cc.Int)
   689  	t.ptrType = t.Config.ABI.Type(cc.Ptr)
   690  
   691  	// if dmesgs {
   692  	// 	dmesg("%v sources for %s", len(sources), fn)
   693  	// 	for i, v := range sources {
   694  	// 		dmesg("#%v: Name %s:", i+1, v.Name)
   695  	// 		switch {
   696  	// 		case v.Value != "":
   697  	// 			dmesg("Value:\n%s", v.Value)
   698  	// 		default:
   699  	// 			switch filepath.Ext(v.Name) {
   700  	// 			case ".c", ".h":
   701  	// 				b, err := ioutil.ReadFile(v.Name)
   702  	// 				switch {
   703  	// 				case err != nil:
   704  	// 					dmesg("error: %s", err)
   705  	// 				default:
   706  	// 					dmesg("Value:\n%s", b)
   707  	// 				}
   708  	// 			}
   709  	// 		}
   710  	// 	}
   711  	// }
   712  
   713  	t.wr = w
   714  	q := newQBE(t)
   715  
   716  	defer func() {
   717  		if e := recover(); e != nil && err == nil {
   718  			err = fmt.Errorf("%v\n%s", e, debug.Stack())
   719  		}
   720  	}()
   721  
   722  	q.gen()
   723  
   724  	if len(q.externalAsm) != 0 && err == nil {
   725  		err = fmt.Errorf("%v: assembler in C not supported", q.pos(q.externalAsm[0]))
   726  	}
   727  	return err
   728  }
   729  
   730  func main() {
   731  	if dmesgs {
   732  		dmesg("main entered %v", os.Args)
   733  	}
   734  	t, err := newTask(os.Args)
   735  	if err != nil {
   736  		fmt.Fprintln(os.Stderr, err)
   737  		if dmesgs {
   738  			dmesg("%v:\nmain exiting: 1", err)
   739  		}
   740  		os.Exit(1)
   741  	}
   742  
   743  	rc := t.main(os.Stdout, os.Stderr)
   744  	if dmesgs {
   745  		dmesg("main exiting: %v", rc)
   746  	}
   747  	os.Exit(rc)
   748  }