代码拉取完成,页面将自动刷新
// Copyright 2016 The CC Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run generate.go
//go:generate golex -o trigraphs.go trigraphs.l
//go:generate golex -o scanner.go scanner.l
//go:generate stringer -type Kind
//go:generate stringer -type Linkage
//go:generate stringer -type Namespace
//go:generate stringer -type Scope
//go:generate go run generate.go -2
// Package cc is a C99 compiler front end.
//
// Changelog
//
// 2018-07-01 This package is no longer maintained. Please see the v2 version at
//
// https://github.com/cznic/cc/v2
//
// Links
//
// Referenced from elsewhere:
//
// [0]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
// [1]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1406.pdf
// [2]: https://github.com/rsc/c2go/blob/fc8cbfad5a47373828c81c7a56cccab8b221d310/cc/cc.y
// [3]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
package cc
import (
"bufio"
"bytes"
"fmt"
"go/token"
"os"
"os/exec"
"runtime"
"strings"
"github.com/cznic/golex/lex"
"github.com/cznic/mathutil"
"github.com/cznic/strutil"
"github.com/cznic/xc"
)
const (
fakeTime = "__TESTING_TIME__"
gccPredefine = `
#define __PRETTY_FUNCTION__ __func__
#define __asm asm
#define __attribute(x)
#define __attribute__(x)
#define __builtin___memcpy_chk(x, y, z, t) __BUILTIN___MEMCPY_CHK()
#define __builtin___memset_chk(x, y, z, ...) __BUILTIN___MEMSET_CHK()
#define __builtin_alloca(x) __BUILTIN_ALLOCA()
#define __builtin_classify_type(x) __BUILTIN_CLASSIFY_TYPE()
#define __builtin_constant_p(exp) __BUILTIN_CONSTANT_P()
#define __builtin_isgreater(x, y) __BUILTIN_ISGREATER()
#define __builtin_isless(x, y) __BUILTIN_ISLESS()
#define __builtin_isunordered(x, y) __BUILTIN_ISUNORDERED()
#define __builtin_longjmp(x, y) __BUILTIN_LONGJMP()
#define __builtin_malloc(x) __BUILTIN_MALLOC()
#define __builtin_memmove(x, y, z) __BUILTIN_MEMMOVE()
#define __builtin_mempcpy(x, y, z) __BUILTIN_MEMPCPY()
#define __builtin_mul_overflow(a, b, c) __BUILTIN_MUL_OVERFLOW()
#define __builtin_offsetof(type, member) ((%[1]v)(&((type *)0)->member))
#define __builtin_signbit(x) __BUILTIN_SIGNBIT()
#define __builtin_va_arg(ap, type) ( *( type* )ap )
#define __builtin_va_end(x)
#define __builtin_va_list void*
#define __builtin_va_start(x, y)
#define __complex _Complex
#define __complex__ _Complex
#define __const
#define __extension__
#define __imag__
#define __inline inline
#define __real(x) __REAL()
#define __real__
#define __restrict
#define __sync_fetch_and_add(x, y, ...) __SYNC_FETCH_AND_ADD()
#define __sync_val_compare_and_swap(x, y, z, ...) __SYNC_VAL_COMPARE_AND_SWAP()
#define __typeof typeof
#define __volatile volatile
%[1]v __builtin_object_size (void*, int);
%[1]v __builtin_strlen(char*);
%[1]v __builtin_strspn(char*, char*);
_Bool __BUILTIN_MUL_OVERFLOW();
char* __builtin___stpcpy_chk(char*, char*, %[1]v);
char* __builtin_stpcpy(char*, char*);
char* __builtin_strchr(char*, int);
char* __builtin_strcpy(char*, char*);
char* __builtin_strdup(char*);
char* __builtin_strncpy(char*, char*, %[1]v);
double _Complex __builtin_cpow(double _Complex, _Complex double);
double __REAL();
double __builtin_copysign(double, double);
double __builtin_copysignl(long double, long double);
double __builtin_inff();
double __builtin_modf(double, double*);
double __builtin_modfl(long double, long double*);
double __builtin_nanf(char *);
float _Complex __builtin_conjf(float _Complex);
float __builtin_ceilf(float);
float __builtin_copysignf(float, float);
float __builtin_modff(float, float*);
int __BUILTIN_CLASSIFY_TYPE();
int __BUILTIN_CONSTANT_P();
int __BUILTIN_ISGREATER();
int __BUILTIN_ISLESS();
int __BUILTIN_ISUNORDERED();
int __BUILTIN_SIGNBIT();
int __builtin___snprintf_chk (char*, %[1]v, int, %[1]v, char*, ...);
int __builtin___sprintf_chk (char*, int, %[1]v, char*, ...);
int __builtin___vsnprintf_chk (char*, %[1]v, int, %[1]v, char*, void*);
int __builtin___vsprintf_chk (char*, int, %[1]v, char*, void*);
int __builtin_abs(int);
int __builtin_clrsb(int);
int __builtin_clrsbl(long);
int __builtin_clrsbll(long long);
int __builtin_clz(unsigned int);
int __builtin_clzl(unsigned long);
int __builtin_clzll(unsigned long long);
int __builtin_constant_p (exp);
int __builtin_ctz(unsigned int x);
int __builtin_ctzl(unsigned long);
int __builtin_ctzll(unsigned long long);
int __builtin_ffs(int);
int __builtin_ffsl(long);
int __builtin_ffsll(long long);
int __builtin_isinf(double);
int __builtin_isinff(float);
int __builtin_isinfl(long double);
int __builtin_memcmp(void*, void*, %[1]v);
int __builtin_parity (unsigned);
int __builtin_parityl(unsigned long);
int __builtin_parityll (unsigned long long);
int __builtin_popcount (unsigned int x);
int __builtin_popcountl (unsigned long);
int __builtin_popcountll (unsigned long long);
int __builtin_printf(char*, ...);
int __builtin_puts(char*);
int __builtin_setjmp(void*);
int __builtin_strcmp(char*, char*);
int __builtin_strncmp(char*, char*, %[1]v);
long __builtin_expect(long, long);
long long strlen (char*);
unsigned __builtin_bswap32 (unsigned x);
unsigned long long __builtin_bswap64 (unsigned long long x);
unsigned short __builtin_bswap16 (unsigned short x);
void __BUILTIN_LONGJMP();
void __SYNC_FETCH_AND_ADD();
void __SYNC_VAL_COMPARE_AND_SWAP();
void __builtin_abort(void);
void __builtin_bcopy(void*, void*, %[1]v);
void __builtin_bzero(void*, %[1]v);
void __builtin_prefetch (void*, ...);
void __builtin_stack_restore(void*);
void __builtin_trap (void);
void __builtin_unreachable (void);
void __builtin_unwind_init();
void __builtin_va_arg_pack ();
void __builtin_va_copy(void*, void*);
void* __BUILTIN_ALLOCA();
void* __BUILTIN_MALLOC();
void* __BUILTIN_MEMMOVE();
void* __BUILTIN_MEMPCPY();
void* __BUILTIN___MEMCPY_CHK();
void* __BUILTIN___MEMSET_CHK();
void* __builtin_alloca(int);
void* __builtin_apply (void (*)(), void*, %[1]v);
void* __builtin_apply_args();
void* __builtin_extract_return_addr(void *);
void* __builtin_frame_address(unsigned int);
void* __builtin_memcpy(void*, void*, long long);
void* __builtin_memset(void*, int, long long);
void* __builtin_return_address (unsigned int);
void* __builtin_stack_save();
void* memcpy(void*, void*, long long);
void* memset(void*, int, long long);
`
)
// ImportPath returns the import path of this package or an error, if any.
func ImportPath() (string, error) { return strutil.ImportPath() }
// HostConfig executes HostCppConfig with the cpp argument set to "cpp". For
// more info please see the documentation of HostCppConfig.
func HostConfig(opts ...string) (predefined string, includePaths, sysIncludePaths []string, err error) {
return HostCppConfig("cpp", opts...)
}
// HostCppConfig returns the system C preprocessor configuration, or an error,
// if any. The configuration is obtained by running the cpp command. For the
// predefined macros list the '-dM' options is added. For the include paths
// lists, the option '-v' is added and the output is parsed to extract the
// "..." include and <...> include paths. To add any other options to cpp, list
// them in opts.
//
// The function relies on a POSIX compatible C preprocessor installed.
// Execution of HostConfig is not free, so caching the results is recommended
// whenever possible.
func HostCppConfig(cpp string, opts ...string) (predefined string, includePaths, sysIncludePaths []string, err error) {
args := append(append([]string{"-dM"}, opts...), os.DevNull)
// cross-compile e.g. win64 -> win32
if runtime.GOARCH == "386" {
args = append(args, "-m32")
}
pre, err := exec.Command(cpp, args...).Output()
if err != nil {
return "", nil, nil, err
}
args = append(append([]string{"-v"}, opts...), os.DevNull)
out, err := exec.Command(cpp, args...).CombinedOutput()
if err != nil {
return "", nil, nil, err
}
sep := "\n"
if runtime.GOOS == "windows" {
sep = "\r\n"
}
a := strings.Split(string(out), sep)
for i := 0; i < len(a); {
switch a[i] {
case "#include \"...\" search starts here:":
loop:
for i = i + 1; i < len(a); {
switch v := a[i]; {
case strings.HasPrefix(v, "#") || v == "End of search list.":
break loop
default:
includePaths = append(includePaths, strings.TrimSpace(v))
i++
}
}
case "#include <...> search starts here:":
for i = i + 1; i < len(a); {
switch v := a[i]; {
case strings.HasPrefix(v, "#") || v == "End of search list.":
return string(pre), includePaths, sysIncludePaths, nil
default:
sysIncludePaths = append(sysIncludePaths, strings.TrimSpace(v))
i++
}
}
default:
i++
}
}
return "", nil, nil, fmt.Errorf("failed parsing %s -v output", cpp)
}
type tweaks struct {
allowCompatibleTypedefRedefinitions bool // typedef int foo; typedef int foo;
comments map[token.Pos]int //
devTest bool //
disablePredefinedLineMacro bool // __LINE__ will not expand.
enableAlignof bool //
enableAlternateKeywords bool // __asm__ etc.
enableAnonymousStructFields bool //
enableAsm bool //
enableBuiltinClassifyType bool // __builtin_classify_type(expr)
enableBuiltinConstantP bool // __builtin_constant_p(expr)
enableComputedGotos bool // var = &&label; goto *var;
enableDefineOmitCommaBeforeDDD bool // #define foo(a, b...)
enableDlrInIdentifiers bool // foo$bar
enableEmptyDeclarations bool // ; // C++11
enableEmptyDefine bool // #define
enableEmptyStructs bool // struct foo {};
enableImaginarySuffix bool // 4.2i
enableImplicitFuncDef bool // int f() { return g(); } int g() { return 42; }
enableImplicitIntType bool // eg. 'static i;' is the same as 'static int i;'.
enableIncludeNext bool //
enableLegacyDesignators bool // { a: 42 }
enableNonConstStaticInitExpressions bool // static int *p = &i;
enableNoreturn bool //
enableOmitConditionalOperand bool // x ? : y == x ? x : y
enableOmitFuncArgTypes bool // f(a) becomes the same as int f(int a).
enableOmitFuncRetType bool // f() becomes the same as int f().
enableParenCompoundStmt bool // ({...}), see [3]
enableStaticAssert bool // _Static_assert
enableTrigraphs bool // ??=define foo(bar)
enableTypeof bool //
enableUndefExtraTokens bool // #undef foo(bar)
enableUnsignedEnums bool // If no enum member is negative, enum type will be unsigned.
enableWarnings bool // #warning
enableWideBitFieldTypes bool // long long v : 2;
enableWideEnumValues bool // enum { v = X } for X wider than 32bits
gccEmu bool //
mode99c bool //
preprocessOnly bool //
}
func (t *tweaks) doGccEmu() *tweaks {
t.allowCompatibleTypedefRedefinitions = true
t.enableAlignof = true
t.enableAlternateKeywords = true
t.enableAnonymousStructFields = true
t.enableAsm = true
t.enableDefineOmitCommaBeforeDDD = true
t.enableDlrInIdentifiers = true
t.enableEmptyDefine = true
t.enableEmptyStructs = true
t.enableIncludeNext = true
t.enableNonConstStaticInitExpressions = true
t.enableNoreturn = true
t.enableOmitFuncRetType = true
t.enableStaticAssert = true
t.enableTypeof = true
t.enableUndefExtraTokens = true
t.enableWarnings = false
return t
}
func exampleAST(rule int, src string) interface{} {
report := xc.NewReport()
report.IgnoreErrors = true
r := bytes.NewBufferString(src)
r0, _, _ := r.ReadRune()
lx, err := newLexer(
fmt.Sprintf("example%v.c", rule),
len(src)+1, // Plus final injected NL
r,
report,
(&tweaks{gccEmu: true}).doGccEmu(),
)
lx.Unget(lex.NewChar(token.Pos(lx.File.Base()), r0))
lx.model = &Model{ // 64 bit
Items: map[Kind]ModelItem{
Ptr: {8, 8, 8, nil},
Void: {0, 1, 1, nil},
Char: {1, 1, 1, nil},
SChar: {1, 1, 1, nil},
UChar: {1, 1, 1, nil},
Short: {2, 2, 2, nil},
UShort: {2, 2, 2, nil},
Int: {4, 4, 4, nil},
UInt: {4, 4, 4, nil},
Long: {8, 8, 8, nil},
ULong: {8, 8, 8, nil},
LongLong: {8, 8, 8, nil},
ULongLong: {8, 8, 8, nil},
Float: {4, 4, 4, nil},
Double: {8, 8, 8, nil},
LongDouble: {8, 8, 8, nil},
Bool: {1, 1, 1, nil},
FloatComplex: {8, 8, 8, nil},
DoubleComplex: {16, 16, 16, nil},
LongDoubleComplex: {16, 16, 16, nil},
},
tweaks: &tweaks{},
}
lx.model.initialize(lx)
if err != nil {
panic(err)
}
lx.exampleRule = rule
yyParse(lx)
return lx.example
}
func ppParseString(fn, src string, report *xc.Report, tweaks *tweaks) (*PreprocessingFile, error) {
sz := len(src)
lx, err := newLexer(fn, sz+1, bytes.NewBufferString(src), report, tweaks)
if err != nil {
return nil, err
}
lx.Unget(lex.NewChar(token.Pos(lx.File.Base()), PREPROCESSING_FILE))
yyParse(lx)
return lx.preprocessingFile, nil
}
func ppParse(fn string, report *xc.Report, tweaks *tweaks) (*PreprocessingFile, error) {
o := xc.Files.Once(fn, func() interface{} {
f, err := os.Open(fn)
if err != nil {
return err
}
defer f.Close()
fi, err := os.Stat(fn)
if err != nil {
return nil
}
sz := fi.Size()
if sz > mathutil.MaxInt-1 {
return fmt.Errorf("%s: file size too big: %v", fn, sz)
}
lx, err := newLexer(fn, int(sz)+1, bufio.NewReader(f), report, tweaks)
if err != nil {
return err
}
lx.Unget(lex.NewChar(token.Pos(lx.File.Base()), PREPROCESSING_FILE))
if yyParse(lx) != 0 {
return report.Errors(true)
}
return lx.preprocessingFile
})
switch r := o.Value(); x := r.(type) {
case error:
return nil, x
case *PreprocessingFile:
return x, nil
default:
panic("internal error")
}
}
// Opt is a configuration/setup function that can be passed to the Parser
// function.
type Opt func(*lexer)
// KeepComments makes the parser keep comments.
func KeepComments() Opt {
return func(l *lexer) { l.tweaks.comments = map[token.Pos]int{} }
}
// EnableBuiltinClassifyType makes the parser handle specially
//
// __builtin_constant_p(expr)
//
// See https://gcc.gnu.org/onlinedocs/gccint/Varargs.html
func EnableBuiltinClassifyType() Opt {
return func(l *lexer) { l.tweaks.enableBuiltinClassifyType = true }
}
// Mode99c turns on support for the 99c compiler.
func Mode99c() Opt {
return func(l *lexer) { l.tweaks.mode99c = true }
}
// EnableBuiltinConstantP makes the parser handle specially
//
// __builtin_constant_p(expr)
//
// See https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
func EnableBuiltinConstantP() Opt {
return func(l *lexer) { l.tweaks.enableBuiltinConstantP = true }
}
// EnableImplicitIntType makes the parser accept non standard omitting type
// specifier. For example
//
// static i;
//
// becomes the same as
//
// static int i;
//
func EnableImplicitIntType() Opt {
return func(l *lexer) { l.tweaks.enableImplicitIntType = true }
}
// EnableOmitConditionalOperand makes the parser accept non standard
//
// x ? : y
//
// See https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Conditionals.html#Conditionals
func EnableOmitConditionalOperand() Opt {
return func(l *lexer) { l.tweaks.enableOmitConditionalOperand = true }
}
// EnableComputedGotos makes the parser accept non standard
//
// variable = &&label;
// goto *variable;
//
// See https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Labels-as-Values.html
func EnableComputedGotos() Opt {
return func(l *lexer) { l.tweaks.enableComputedGotos = true }
}
// EnableUnsignedEnums makes the parser handle choose unsigned int as the type
// of an enumeration with no negative members.
func EnableUnsignedEnums() Opt {
return func(l *lexer) { l.tweaks.enableUnsignedEnums = true }
}
// EnableLegacyDesignators makes the parser accept legacy designators
//
// { a: 42 } // Obsolete since GCC 2.5, standard is { .a=42 }
//
// See https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html
func EnableLegacyDesignators() Opt {
return func(l *lexer) { l.tweaks.enableLegacyDesignators = true }
}
// AllowCompatibleTypedefRedefinitions makes the parser accept compatible
// typedef redefinitions.
//
// typedef int foo;
// typedef int foo; // ok with this option.
// typedef long int foo; // never ok.
//
func AllowCompatibleTypedefRedefinitions() Opt {
return func(l *lexer) { l.tweaks.allowCompatibleTypedefRedefinitions = true }
}
// EnableParenthesizedCompoundStatemen makes the parser accept non standard
//
// ({ ... })
//
// as an expression. See [3].
func EnableParenthesizedCompoundStatemen() Opt {
return func(l *lexer) { l.tweaks.enableParenCompoundStmt = true }
}
// EnableImaginarySuffix makes the parser accept non standard
//
// 4.2i, 5.6j etc
//
// See https://gcc.gnu.org/onlinedocs/gcc/Complex.html
func EnableImaginarySuffix() Opt {
return func(l *lexer) { l.tweaks.enableImaginarySuffix = true }
}
// EnableNonConstStaticInitExpressions makes the parser accept non standard
//
// static int i = f();
//
// [0], 6.7.8/4: All the expressions in an initializer for an object that has
// static storage duration shall be constant expressions or string literals.
func EnableNonConstStaticInitExpressions() Opt {
return func(l *lexer) { l.tweaks.enableNonConstStaticInitExpressions = true }
}
// EnableAnonymousStructFields makes the parser accept non standard
//
// struct {
// int i;
// struct {
// int j;
// };
// int k;
// };
func EnableAnonymousStructFields() Opt {
return func(l *lexer) { l.tweaks.enableAnonymousStructFields = true }
}
// EnableOmitFuncRetType makes the parser accept non standard
//
// f() // Same as int f().
func EnableOmitFuncRetType() Opt {
return func(l *lexer) { l.tweaks.enableOmitFuncRetType = true }
}
// EnableOmitFuncArgTypes makes the parser accept non standard
//
// f(a) // Same as int f(int a).
func EnableOmitFuncArgTypes() Opt {
return func(l *lexer) { l.tweaks.enableOmitFuncArgTypes = true }
}
// EnableEmptyDeclarations makes the parser accept non standard
//
// ; // C++11 empty declaration
func EnableEmptyDeclarations() Opt {
return func(l *lexer) { l.tweaks.enableEmptyDeclarations = true }
}
// EnableIncludeNext makes the parser accept non standard
//
// #include_next "foo.h"
func EnableIncludeNext() Opt {
return func(l *lexer) { l.tweaks.enableIncludeNext = true }
}
// EnableDefineOmitCommaBeforeDDD makes the parser accept non standard
//
// #define foo(a, b...) // Note the missing comma after identifier list.
func EnableDefineOmitCommaBeforeDDD() Opt {
return func(l *lexer) { l.tweaks.enableDefineOmitCommaBeforeDDD = true }
}
// EnableAlternateKeywords makes the parser accept, for example, non standard
//
// __asm__
//
// as an equvalent of keyowrd asm (which first hast be permitted by EnableAsm).
func EnableAlternateKeywords() Opt {
return func(l *lexer) { l.tweaks.enableAlternateKeywords = true }
}
// EnableDlrInIdentifiers makes the parser accept non standard
//
// int foo$bar
func EnableDlrInIdentifiers() Opt {
return func(l *lexer) { l.tweaks.enableDlrInIdentifiers = true }
}
// EnableEmptyDefine makes the parser accept non standard
//
// #define
func EnableEmptyDefine() Opt {
return func(l *lexer) { l.tweaks.enableEmptyDefine = true }
}
// EnableImplicitFuncDef makes the parser accept non standard
//
// int f() {
// return g(); // g is undefined, but assumed to be returning int.
// }
func EnableImplicitFuncDef() Opt {
return func(l *lexer) { l.tweaks.enableImplicitFuncDef = true }
}
// EnableEmptyStructs makes the parser accept non standard
//
// struct foo {};
func EnableEmptyStructs() Opt {
return func(l *lexer) { l.tweaks.enableEmptyStructs = true }
}
// EnableUndefExtraTokens makes the parser accept non standard
//
// #undef foo(bar)
func EnableUndefExtraTokens() Opt {
return func(l *lexer) { l.tweaks.enableUndefExtraTokens = true }
}
// EnableWideEnumValues makes the parser accept non standard
//
// enum { v = X }; for X wider than 32 bits.
func EnableWideEnumValues() Opt {
return func(l *lexer) { l.tweaks.enableWideEnumValues = true }
}
// EnableWideBitFieldTypes makes the parser accept non standard bitfield
// types (i.e, long long and unsigned long long).
//
// unsigned long long bits : 2;
func EnableWideBitFieldTypes() Opt {
return func(l *lexer) { l.tweaks.enableWideBitFieldTypes = true }
}
// SysIncludePaths option configures where to search for system include files
// (eg. <name.h>). Multiple SysIncludePaths options may be used, the resulting
// search path list is produced by appending the option arguments in order of
// appearance.
func SysIncludePaths(paths []string) Opt {
return func(l *lexer) {
var err error
if l.sysIncludePaths, err = dedupAbsPaths(append(l.sysIncludePaths, fromSlashes(paths)...)); err != nil {
l.report.Err(0, "synIncludepaths option: %v", err)
}
l.sysIncludePaths = l.sysIncludePaths[:len(l.sysIncludePaths):len(l.sysIncludePaths)]
}
}
// IncludePaths option configures where to search for include files (eg.
// "name.h"). Multiple IncludePaths options may be used, the resulting search
// path list is produced by appending the option arguments in order of
// appearance.
func IncludePaths(paths []string) Opt {
return func(l *lexer) {
var err error
if l.includePaths, err = dedupAbsPaths(append(l.includePaths, fromSlashes(paths)...)); err != nil {
l.report.Err(0, "includepaths option: %v", err)
}
l.includePaths = l.includePaths[:len(l.includePaths):len(l.includePaths)]
}
}
// YyDebug sets the parser debug level.
func YyDebug(n int) Opt {
return func(*lexer) { yyDebug = n }
}
// Cpp registers a preprocessor hook function which is called for every line,
// or group of lines the preprocessor produces before it is consumed by the
// parser. The token slice must not be modified by the hook.
func Cpp(f func([]xc.Token)) Opt {
return func(lx *lexer) { lx.cpp = f }
}
// ErrLimit limits the number of calls to the error reporting methods. After
// the limit is reached, all errors are reported using log.Print and then
// log.Fatal() is called with a message about too many errors. To disable
// error limit, set ErrLimit to value less or equal zero. Default value is 10.
func ErrLimit(n int) Opt {
return func(lx *lexer) { lx.report.ErrLimit = n }
}
// Trigraphs enables processing of trigraphs.
func Trigraphs() Opt { return func(lx *lexer) { lx.tweaks.enableTrigraphs = true } }
// EnableAsm enables recognizing the reserved word asm.
func EnableAsm() Opt { return func(lx *lexer) { lx.tweaks.enableAsm = true } }
// EnableNoreturn enables recognizing the reserved word _Noreturn.
func EnableNoreturn() Opt { return func(lx *lexer) { lx.tweaks.enableNoreturn = true } }
// EnableTypeOf enables recognizing the reserved word typeof.
func EnableTypeOf() Opt { return func(lx *lexer) { lx.tweaks.enableTypeof = true } }
// EnableAlignOf enables recognizing the reserved word _Alignof.
func EnableAlignOf() Opt { return func(lx *lexer) { lx.tweaks.enableAlignof = true } }
// EnableStaticAssert enables recognizing the reserved word _Static_assert.
func EnableStaticAssert() Opt { return func(lx *lexer) { lx.tweaks.enableStaticAssert = true } }
// CrashOnError is an debugging option.
func CrashOnError() Opt { return func(lx *lexer) { lx.report.PanicOnError = true } }
func disableWarnings() Opt { return func(lx *lexer) { lx.tweaks.enableWarnings = false } }
func gccEmu() Opt { return func(lx *lexer) { lx.tweaks.gccEmu = true } }
func getTweaks(dst *tweaks) Opt { return func(lx *lexer) { *dst = *lx.tweaks } }
func nopOpt() Opt { return func(*lexer) {} }
func preprocessOnly() Opt { return func(lx *lexer) { lx.tweaks.preprocessOnly = true } }
func devTest() Opt {
return func(lx *lexer) { lx.tweaks.devTest = true }
}
func disablePredefinedLineMacro() Opt {
return func(lx *lexer) { lx.tweaks.disablePredefinedLineMacro = true }
}
// Parse defines any macros in predefine. Then Parse preprocesses and parses
// the translation unit consisting of files in paths. The m communicates the
// scalar types model and opts allow to amend parser behavior. m cannot be
// reused and passed to Parse again.
func Parse(predefine string, paths []string, m *Model, opts ...Opt) (*TranslationUnit, error) {
if m == nil {
return nil, fmt.Errorf("invalid nil model passed")
}
if m.initialized {
return nil, fmt.Errorf("invalid reused model passed")
}
fromSlashes(paths)
report := xc.NewReport()
lx0 := &lexer{tweaks: &tweaks{enableWarnings: true}, report: report}
for _, opt := range opts {
opt(lx0)
}
m.tweaks = lx0.tweaks
if err := report.Errors(true); err != nil {
return nil, err
}
if lx0.tweaks.devTest {
predefine += fmt.Sprintf(`
#define __DATE__ %q
#define __TIME__ %q
`, xc.Dict.S(idTDate), fakeTime)
}
if t := lx0.tweaks; t.gccEmu {
t.doGccEmu()
}
m.initialize(lx0)
if err := m.sanityCheck(); err != nil {
report.Err(0, "%s", err.Error())
return nil, report.Errors(true)
}
if lx0.tweaks.gccEmu {
dts := debugTypeStrings
debugTypeStrings = false
predefine += fmt.Sprintf(gccPredefine, m.getSizeType(lx0))
debugTypeStrings = dts
}
tweaks := lx0.tweaks
predefined, err := ppParseString("<predefine>", predefine, report, tweaks)
if err != nil {
return nil, err
}
ch := make(chan []xc.Token, 1000)
macros := newMacros()
stop := make(chan int, 1)
go func() {
defer close(ch)
newPP(ch, lx0.includePaths, lx0.sysIncludePaths, macros, false, m, report, tweaks).preprocessingFile(predefined)
for _, path := range paths {
select {
case <-stop:
return
default:
}
pf, err := ppParse(path, report, tweaks)
if err != nil {
report.Err(0, err.Error())
return
}
newPP(ch, lx0.includePaths, lx0.sysIncludePaths, macros, true, m, report, tweaks).preprocessingFile(pf)
}
}()
if err := report.Errors(true); err != nil { // Do not parse if preprocessing already failed.
go func() {
for range ch { // Drain.
}
}()
stop <- 1
return nil, err
}
lx := newSimpleLexer(lx0.cpp, report, tweaks)
lx.ch = ch
lx.state = lsTranslationUnit0
lx.model = m
if lx.tweaks.preprocessOnly {
var lval yySymType
for lval.Token.Rune != lex.RuneEOF {
lx.Lex(&lval)
}
return nil, report.Errors(true)
}
yyParse(lx)
stop <- 1
for range ch { // Drain.
}
if tu := lx.translationUnit; tu != nil {
tu.Macros = macros.macros()
tu.Model = m
tu.Comments = lx0.tweaks.comments
if c := tu.Comments; c != nil {
for _, v := range tu.Declarations.Identifiers {
switch x := v.Node.(type) {
case *DirectDeclarator:
pos0 := x.Declarator.Pos()
if !pos0.IsValid() {
pos0 = x.Pos()
}
if !pos0.IsValid() {
break
}
if comment(lx0.tweaks, x, x.Declarator) != 0 {
break
}
for p := x.prev; p != nil; {
y := p.Node.(*DirectDeclarator)
if n := comment(lx0.tweaks, y, y.Declarator); n != 0 {
pos := y.DirectDeclarator.Pos()
if !pos.IsValid() {
pos = y.Pos()
}
c[pos0] = n
break
}
p2 := p.Node.(*DirectDeclarator).prev
if p2 == p {
break
}
p = p2
}
default:
panic(fmt.Errorf("%T", x))
}
}
}
}
return lx.translationUnit, report.Errors(true)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。