diff --git a/.gitignore b/.gitignore index 23c58d48f..8d8f4989a 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ backup/ /wrapperhelper/sanundefined /wrapperhelper/src/machine.gen /wrapperhelper/*.h +!/wrapperhelper/example-libc.h # macOS .DS_Store diff --git a/wrapperhelper/README.md b/wrapperhelper/README.md index e543af374..282fdf6c1 100644 --- a/wrapperhelper/README.md +++ b/wrapperhelper/README.md @@ -25,7 +25,9 @@ To use the wrapper helper, run the following command in the folder containing th bin/wrapperhelper -I/path/to/system/include "path_to_support_file" "path_to_private.h" "path_to_private.h" ``` -You may add as many `-I` options as needed. +You may add as many `-I` options as needed. The folders `include-override/` and `include-override/common` are always prioritized, as if they appeared first in the command line. + +You may also use the `-32` and `-64` switches to generate `box32` or `box64` files respectively. Alterately, you can use the `--emu arch` and `--target arch` options to select more precisely the emlated and executing platforms, though only `x86`, `x86_64` and `aarch64` are supported for now. By default, everything is as if `-64` was supplied. The first file is a `C` file containing every declaration required. The second file is the "requests" input. The third file is the output file, which may be a different file. @@ -100,30 +102,25 @@ The reading and writing of the `_private.h` files is implemented in `generator.c ## Known issues -This project only works for `box64`; more work is required for this to be compatible with `box32`. - Only native structures are read. This means that the current version of `wrapperhelper` does not detect an issue when a structure has different members or alignments in two different architectures. No checking of signatures under `#ifdef`s is made. -Line numbers are missing entirely. For most errors, the corresponding file is not written with the error message. - Phase 5 is partially implemented, but could be greatly improved. The following features are missing from the generator: -- Large structures as a parameter -- Large structure as a return type (more than 16 bytes) +- Structures with at least two elements as a parameter +- Large structure as a return type (more than 16 bytes on 64bits, or 8 bytes on 32bits) - Atomic types The following features are missing from the preprocessor: - General token concatenation (though the concatenation of two `PTOK_IDENT` works without issue) - Stringify - Skipped unexpected token warnings -- Proper out-of-memory error handling The following features are missing from the parser: -- `_Atomic(type-name)` - `_Alignas(type-name)` and `_Alignas(constant-expression)` - `(type-name){initializer-list}` - Old style function declarations - Function definitions are ignored, not parsed +- Attributes are ignored everywhere (with a `#define __attribute__(_)`) diff --git a/wrapperhelper/include-override/aarch64/stdc-predef.h b/wrapperhelper/include-override/aarch64/stdc-predef.h index b2609a3c7..df1d78b56 100644 --- a/wrapperhelper/include-override/aarch64/stdc-predef.h +++ b/wrapperhelper/include-override/aarch64/stdc-predef.h @@ -123,16 +123,16 @@ //#define __BITINT_MAXWIDTH__ 65535 //#define __CHAR16_TYPE__ short unsigned int //#define __CHAR32_TYPE__ unsigned int -#define __INT8_C(c) c +//#define __INT8_C(c) c #define __INT8_MAX__ 0x7f //#define __INT8_TYPE__ signed char -#define __INT16_C(c) c +//#define __INT16_C(c) c #define __INT16_MAX__ 0x7fff //#define __INT16_TYPE__ short int -#define __INT32_C(c) c +//#define __INT32_C(c) c #define __INT32_MAX__ 0x7fffffff //#define __INT32_TYPE__ int -#define __INT64_C(c) c ## L +//#define __INT64_C(c) c ## L #define __INT64_MAX__ 0x7fffffffffffffffL //#define __INT64_TYPE__ long int #define __INT_FAST8_MAX__ 0x7f diff --git a/wrapperhelper/include-override/common/stdc-predef.h b/wrapperhelper/include-override/common/stdc-predef.h index ace6ec7d8..3484bbce8 100644 --- a/wrapperhelper/include-override/common/stdc-predef.h +++ b/wrapperhelper/include-override/common/stdc-predef.h @@ -1,4 +1,2 @@ // Ignore all attributes #define __attribute__(_) - -#include_next "stdc-predef.h" diff --git a/wrapperhelper/include-override/x86/bits/pthreadtypes-arch.h b/wrapperhelper/include-override/x86/bits/pthreadtypes-arch.h new file mode 100644 index 000000000..b23ff3b02 --- /dev/null +++ b/wrapperhelper/include-override/x86/bits/pthreadtypes-arch.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2002-2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _BITS_PTHREADTYPES_ARCH_H +#define _BITS_PTHREADTYPES_ARCH_H 1 + +#include + +#ifdef __x86_64__ +# if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# else +# define __SIZEOF_PTHREAD_MUTEX_T 32 +# define __SIZEOF_PTHREAD_ATTR_T 32 +# define __SIZEOF_PTHREAD_RWLOCK_T 44 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# endif +#else +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +#endif +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + +#define __LOCK_ALIGNMENT +#define __ONCE_ALIGNMENT + +#ifndef __x86_64__ +/* Extra attributes for the cleanup functions. */ +# define __cleanup_fct_attribute __attribute__ ((__regparm__ (1))) +#endif + +#endif /* bits/pthreadtypes.h */ diff --git a/wrapperhelper/include-override/x86/stdc-predef.h b/wrapperhelper/include-override/x86/stdc-predef.h new file mode 100644 index 000000000..4f59430af --- /dev/null +++ b/wrapperhelper/include-override/x86/stdc-predef.h @@ -0,0 +1,401 @@ +// C standard +#define __STDC__ 1 +#define __STDC_HOSTED__ 1 +#define __STDC_UTF_16__ 1 +#define __STDC_UTF_32__ 1 +#define __STDC_VERSION__ 201710L +// Generic x86_64 infos +#define __ELF__ 1 +#define __NO_INLINE__ 1 +#define __ORDER_BIG_ENDIAN__ 4321 +#define __ORDER_LITTLE_ENDIAN__ 1234 +#define __ORDER_PDP_ENDIAN__ 3412 +#define __PIC__ 2 +#define __pic__ 2 +#define __PIE__ 2 +#define __pie__ 2 +#define __USER_LABEL_PREFIX__ +#define __gnu_linux__ 1 +#define __linux__ 1 +#define __linux 1 +#define linux 1 +#define __unix__ 1 +#define __unix 1 +#define unix 1 +// GCC +//#define __GCC_ASM_FLAG_OUTPUTS__ 1 +//#define __GCC_ATOMIC_BOOL_LOCK_FREE 2 +//#define __GCC_ATOMIC_CHAR_LOCK_FREE 2 +//#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 +//#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 +//#define __GCC_ATOMIC_INT_LOCK_FREE 2 +//#define __GCC_ATOMIC_LLONG_LOCK_FREE 2 +//#define __GCC_ATOMIC_LONG_LOCK_FREE 2 +//#define __GCC_ATOMIC_POINTER_LOCK_FREE 2 +//#define __GCC_ATOMIC_SHORT_LOCK_FREE 2 +//#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 +//#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 +//#define __GCC_CONSTRUCTIVE_SIZE 64 +//#define __GCC_DESTRUCTIVE_SIZE 64 +//#define __GCC_HAVE_DWARF2_CFI_ASM 1 +//#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 +//#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 +//#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 +//#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 +//#define __GCC_IEC_559 2 +//#define __GCC_IEC_559_COMPLEX 2 +//#define __GNUC__ 14 +//#define __GNUC_EXECUTION_CHARSET_NAME "UTF-8" +//#define __GNUC_MINOR__ 2 +//#define __GNUC_PATCHLEVEL__ 1 +//#define __GNUC_STDC_INLINE__ 1 +//#define __GNUC_WIDE_EXECUTION_CHARSET_NAME "UTF-32LE" +//#define __GXX_ABI_VERSION 1019 +//#define __PRAGMA_REDEFINE_EXTNAME 1 +//#define __VERSION__ "14.2.1 20240805" +// Specific x86_64 architecture +#define __FINITE_MATH_ONLY__ 0 +#define __HAVE_SPECULATION_SAFE_VALUE 1 +#define __ILP32__ 1 +#define _ILP32 1 +#define __REGISTER_PREFIX__ +#define __FXSR__ 1 +#define __LAHF_SAHF__ 1 +#define __MMX__ 1 +#define __SEG_FS 1 +#define __SEG_GS 1 +#define __SSE__ 1 +#define __SSE2__ 1 +#define __SSP_STRONG__ 3 +#define __code_model_32__ 1 +#define __i386__ 1 +#define __i386 1 +#define i386 1 +#define __k8__ 1 +#define __k8 1 +// Atomic +#define __ATOMIC_RELAXED 0 +#define __ATOMIC_CONSUME 1 +#define __ATOMIC_ACQUIRE 2 +#define __ATOMIC_RELEASE 3 +#define __ATOMIC_ACQ_REL 4 +#define __ATOMIC_SEQ_CST 5 +#define __ATOMIC_HLE_ACQUIRE 65536 +#define __ATOMIC_HLE_RELEASE 131072 +// Metainfo on types +#define __BIGGEST_ALIGNMENT__ 16 +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#define __CHAR_BIT__ 8 +#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__ +#define __SIZEOF_SHORT__ 2 +#define __SIZEOF_WCHAR_T__ 4 +#define __SIZEOF_INT__ 4 +#define __SIZEOF_WINT_T__ 4 +#define __SIZEOF_LONG__ 4 +#define __SIZEOF_LONG_LONG__ 8 +#define __SIZEOF_POINTER__ 4 +#define __SIZEOF_PTRDIFF_T__ 4 +#define __SIZEOF_SIZE_T__ 4 +#define __SIZEOF_FLOAT__ 4 +#define __SIZEOF_DOUBLE__ 8 +#define __SIZEOF_LONG_DOUBLE__ 12 +#define __SIZEOF_FLOAT80__ 12 +#define __SIZEOF_FLOAT128__ 16 +// Integers +//#define __BITINT_MAXWIDTH__ 65535 +//#define __CHAR16_TYPE__ short unsigned int +//#define __CHAR32_TYPE__ unsigned int +//#define __INT8_C(c) c +#define __INT8_MAX__ 0x7f +//#define __INT8_TYPE__ signed char +//#define __INT16_C(c) c +#define __INT16_MAX__ 0x7fff +//#define __INT16_TYPE__ short int +//#define __INT32_C(c) c +#define __INT32_MAX__ 0x7fffffff +//#define __INT32_TYPE__ int +//#define __INT64_C(c) c ## LL +#define __INT64_MAX__ 0x7fffffffffffffffLL +//#define __INT64_TYPE__ long long int +#define __INT_FAST8_MAX__ 0x7f +//#define __INT_FAST8_TYPE__ signed char +#define __INT_FAST8_WIDTH__ 8 +#define __INT_FAST16_MAX__ 0x7fffffff +//#define __INT_FAST16_TYPE__ int +#define __INT_FAST16_WIDTH__ 32 +#define __INT_FAST32_MAX__ 0x7fffffff +//#define __INT_FAST32_TYPE__ int +#define __INT_FAST32_WIDTH__ 32 +#define __INT_FAST64_MAX__ 0x7fffffffffffffffLL +//#define __INT_FAST64_TYPE__ long long int +#define __INT_FAST64_WIDTH__ 64 +#define __INT_LEAST8_MAX__ 0x7f +//#define __INT_LEAST8_TYPE__ signed char +#define __INT_LEAST8_WIDTH__ 8 +#define __INT_LEAST16_MAX__ 0x7fff +//#define __INT_LEAST16_TYPE__ short int +#define __INT_LEAST16_WIDTH__ 16 +#define __INT_LEAST32_MAX__ 0x7fffffff +//#define __INT_LEAST32_TYPE__ int +#define __INT_LEAST32_WIDTH__ 32 +#define __INT_LEAST64_MAX__ 0x7fffffffffffffffLL +//#define __INT_LEAST64_TYPE__ long long int +#define __INT_LEAST64_WIDTH__ 64 +#define __INT_MAX__ 0x7fffffff +#define __INT_WIDTH__ 32 +#define __INTMAX_C(c) c ## LL +#define __INTMAX_MAX__ 0x7fffffffffffffffLL +//#define __INTMAX_TYPE__ long long int +#define __INTMAX_WIDTH__ 64 +#define __INTPTR_MAX__ 0x7fffffff +//#define __INTPTR_TYPE__ int +#define __INTPTR_WIDTH__ 32 +#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL +#define __LONG_LONG_WIDTH__ 64 +#define __LONG_MAX__ 0x7fffffffL +#define __LONG_WIDTH__ 32 +#define __PTRDIFF_MAX__ 0x7fffffff +//#define __PTRDIFF_TYPE__ int +#define __PTRDIFF_WIDTH__ 32 +#define __SCHAR_MAX__ 0x7f +#define __SCHAR_WIDTH__ 8 +#define __SHRT_MAX__ 0x7fff +#define __SHRT_WIDTH__ 16 +#define __SIG_ATOMIC_MAX__ 0x7fffffff +#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1) +//#define __SIG_ATOMIC_TYPE__ int +#define __SIG_ATOMIC_WIDTH__ 32 +#define __SIZE_MAX__ 0xffffffffU +//#define __SIZE_TYPE__ unsigned int +#define __SIZE_WIDTH__ 32 +#define __UINT8_C(c) c +#define __UINT8_MAX__ 0xff +//#define __UINT8_TYPE__ unsigned char +#define __UINT16_C(c) c +#define __UINT16_MAX__ 0xffff +//#define __UINT16_TYPE__ short unsigned int +#define __UINT32_C(c) c ## U +#define __UINT32_MAX__ 0xffffffffU +//#define __UINT32_TYPE__ unsigned int +#define __UINT64_C(c) c ## ULL +#define __UINT64_MAX__ 0xffffffffffffffffULL +//#define __UINT64_TYPE__ long long unsigned int +#define __UINT_FAST8_MAX__ 0xff +//#define __UINT_FAST8_TYPE__ unsigned char +#define __UINT_FAST16_MAX__ 0xffffffffU +//#define __UINT_FAST16_TYPE__ unsigned int +#define __UINT_FAST32_MAX__ 0xffffffffU +//#define __UINT_FAST32_TYPE__ unsigned int +#define __UINT_FAST64_MAX__ 0xffffffffffffffffULL +//#define __UINT_FAST64_TYPE__ long long unsigned int +#define __UINT_LEAST8_MAX__ 0xff +//#define __UINT_LEAST8_TYPE__ unsigned char +#define __UINT_LEAST16_MAX__ 0xffff +//#define __UINT_LEAST16_TYPE__ short unsigned int +#define __UINT_LEAST32_MAX__ 0xffffffffU +//#define __UINT_LEAST32_TYPE__ unsigned int +#define __UINT_LEAST64_MAX__ 0xffffffffffffffffULL +//#define __UINT_LEAST64_TYPE__ long long unsigned int +#define __UINTMAX_C(c) c ## ULL +#define __UINTMAX_MAX__ 0xffffffffffffffffULL +//#define __UINTMAX_TYPE__ long long unsigned int +#define __UINTPTR_MAX__ 0xffffffffU +//#define __UINTPTR_TYPE__ unsigned int +#define __WCHAR_MAX__ 0x7fffffffL +#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1) +//#define __WCHAR_TYPE__ long int +#define __WCHAR_WIDTH__ 32 +#define __WINT_MAX__ 0xffffffffU +#define __WINT_MIN__ 0U +//#define __WINT_TYPE__ unsigned int +#define __WINT_WIDTH__ 32 +// Floats +//#define __BFLT16_DECIMAL_DIG__ 4 +//#define __BFLT16_DENORM_MIN__ 9.18354961579912115600575419704879436e-41BF16 +//#define __BFLT16_DIG__ 2 +//#define __BFLT16_EPSILON__ 7.81250000000000000000000000000000000e-3BF16 +//#define __BFLT16_HAS_DENORM__ 1 +//#define __BFLT16_HAS_INFINITY__ 1 +//#define __BFLT16_HAS_QUIET_NAN__ 1 +//#define __BFLT16_IS_IEC_60559__ 0 +//#define __BFLT16_MANT_DIG__ 8 +//#define __BFLT16_MAX_10_EXP__ 38 +//#define __BFLT16_MAX__ 3.38953138925153547590470800371487867e+38BF16 +//#define __BFLT16_MAX_EXP__ 128 +//#define __BFLT16_MIN_10_EXP__ (-37) +//#define __BFLT16_MIN__ 1.17549435082228750796873653722224568e-38BF16 +//#define __BFLT16_MIN_EXP__ (-125) +//#define __BFLT16_NORM_MAX__ 3.38953138925153547590470800371487867e+38BF16 +#define __DBL_DECIMAL_DIG__ 17 +#define __DBL_DENORM_MIN__ ((double)4.94065645841246544176568792868221372e-324L) +#define __DBL_DIG__ 15 +#define __DBL_EPSILON__ ((double)2.22044604925031308084726333618164062e-16L) +#define __DBL_HAS_DENORM__ 1 +#define __DBL_HAS_INFINITY__ 1 +#define __DBL_HAS_QUIET_NAN__ 1 +#define __DBL_IS_IEC_60559__ 1 +#define __DBL_MANT_DIG__ 53 +#define __DBL_MAX_10_EXP__ 308 +#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L) +#define __DBL_MAX_EXP__ 1024 +#define __DBL_MIN_10_EXP__ (-307) +#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L) +#define __DBL_MIN_EXP__ (-1021) +#define __DBL_NORM_MAX__ ((double)1.79769313486231570814527423731704357e+308L) +//#define __DEC32_EPSILON__ 1E-6DF +//#define __DEC32_MANT_DIG__ 7 +//#define __DEC32_MAX__ 9.999999E96DF +//#define __DEC32_MAX_EXP__ 97 +//#define __DEC32_MIN__ 1E-95DF +//#define __DEC32_MIN_EXP__ (-94) +//#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF +//#define __DEC64_EPSILON__ 1E-15DD +//#define __DEC64_MANT_DIG__ 16 +//#define __DEC64_MAX__ 9.999999999999999E384DD +//#define __DEC64_MAX_EXP__ 385 +//#define __DEC64_MIN__ 1E-383DD +//#define __DEC64_MIN_EXP__ (-382) +//#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD +//#define __DEC128_EPSILON__ 1E-33DL +//#define __DEC128_MANT_DIG__ 34 +//#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL +//#define __DEC128_MAX_EXP__ 6145 +//#define __DEC128_MIN__ 1E-6143DL +//#define __DEC128_MIN_EXP__ (-6142) +//#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL +//#define __DEC_EVAL_METHOD__ 2 +//#define __DECIMAL_BID_FORMAT__ 1 +//#define __DECIMAL_DIG__ 21 +//#define __FLT16_DECIMAL_DIG__ 5 +//#define __FLT16_DENORM_MIN__ 5.96046447753906250000000000000000000e-8F16 +//#define __FLT16_DIG__ 3 +//#define __FLT16_EPSILON__ 9.76562500000000000000000000000000000e-4F16 +//#define __FLT16_HAS_DENORM__ 1 +//#define __FLT16_HAS_INFINITY__ 1 +//#define __FLT16_HAS_QUIET_NAN__ 1 +//#define __FLT16_IS_IEC_60559__ 1 +//#define __FLT16_MANT_DIG__ 11 +//#define __FLT16_MAX_10_EXP__ 4 +//#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16 +//#define __FLT16_MAX_EXP__ 16 +//#define __FLT16_MIN_10_EXP__ (-4) +//#define __FLT16_MIN__ 6.10351562500000000000000000000000000e-5F16 +//#define __FLT16_MIN_EXP__ (-13) +//#define __FLT16_NORM_MAX__ 6.55040000000000000000000000000000000e+4F16 +//#define __FLT32_DECIMAL_DIG__ 9 +//#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32 +//#define __FLT32_DIG__ 6 +//#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32 +//#define __FLT32_HAS_DENORM__ 1 +//#define __FLT32_HAS_INFINITY__ 1 +//#define __FLT32_HAS_QUIET_NAN__ 1 +//#define __FLT32_IS_IEC_60559__ 1 +//#define __FLT32_MANT_DIG__ 24 +//#define __FLT32_MAX_10_EXP__ 38 +//#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32 +//#define __FLT32_MAX_EXP__ 128 +//#define __FLT32_MIN_10_EXP__ (-37) +//#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32 +//#define __FLT32_MIN_EXP__ (-125) +//#define __FLT32_NORM_MAX__ 3.40282346638528859811704183484516925e+38F32 +//#define __FLT32X_DECIMAL_DIG__ 17 +//#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x +//#define __FLT32X_DIG__ 15 +//#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x +//#define __FLT32X_HAS_DENORM__ 1 +//#define __FLT32X_HAS_INFINITY__ 1 +//#define __FLT32X_HAS_QUIET_NAN__ 1 +//#define __FLT32X_IS_IEC_60559__ 1 +//#define __FLT32X_MANT_DIG__ 53 +//#define __FLT32X_MAX_10_EXP__ 308 +//#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x +//#define __FLT32X_MAX_EXP__ 1024 +//#define __FLT32X_MIN_10_EXP__ (-307) +//#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x +//#define __FLT32X_MIN_EXP__ (-1021) +//#define __FLT32X_NORM_MAX__ 1.79769313486231570814527423731704357e+308F32x +//#define __FLT64_DECIMAL_DIG__ 17 +//#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64 +//#define __FLT64_DIG__ 15 +//#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64 +//#define __FLT64_HAS_DENORM__ 1 +//#define __FLT64_HAS_INFINITY__ 1 +//#define __FLT64_HAS_QUIET_NAN__ 1 +//#define __FLT64_IS_IEC_60559__ 1 +//#define __FLT64_MANT_DIG__ 53 +//#define __FLT64_MAX_10_EXP__ 308 +//#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64 +//#define __FLT64_MAX_EXP__ 1024 +//#define __FLT64_MIN_10_EXP__ (-307) +//#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64 +//#define __FLT64_MIN_EXP__ (-1021) +//#define __FLT64_NORM_MAX__ 1.79769313486231570814527423731704357e+308F64 +//#define __FLT64X_DECIMAL_DIG__ 21 +//#define __FLT64X_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951F64x +//#define __FLT64X_DIG__ 18 +//#define __FLT64X_EPSILON__ 1.08420217248550443400745280086994171e-19F64x +//#define __FLT64X_HAS_DENORM__ 1 +//#define __FLT64X_HAS_INFINITY__ 1 +//#define __FLT64X_HAS_QUIET_NAN__ 1 +//#define __FLT64X_IS_IEC_60559__ 1 +//#define __FLT64X_MANT_DIG__ 64 +//#define __FLT64X_MAX_10_EXP__ 4932 +//#define __FLT64X_MAX__ 1.18973149535723176502126385303097021e+4932F64x +//#define __FLT64X_MAX_EXP__ 16384 +//#define __FLT64X_MIN_10_EXP__ (-4931) +//#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x +//#define __FLT64X_MIN_EXP__ (-16381) +//#define __FLT64X_NORM_MAX__ 1.18973149535723176502126385303097021e+4932F64x +//#define __FLT128_DECIMAL_DIG__ 36 +//#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128 +//#define __FLT128_DIG__ 33 +//#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128 +//#define __FLT128_HAS_DENORM__ 1 +//#define __FLT128_HAS_INFINITY__ 1 +//#define __FLT128_HAS_QUIET_NAN__ 1 +//#define __FLT128_IS_IEC_60559__ 1 +//#define __FLT128_MANT_DIG__ 113 +//#define __FLT128_MAX_10_EXP__ 4932 +//#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128 +//#define __FLT128_MAX_EXP__ 16384 +//#define __FLT128_MIN_10_EXP__ (-4931) +//#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128 +//#define __FLT128_MIN_EXP__ (-16381) +//#define __FLT128_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F128 +#define __FLT_DECIMAL_DIG__ 9 +#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F +#define __FLT_DIG__ 6 +#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F +#define __FLT_EVAL_METHOD__ 2 +#define __FLT_EVAL_METHOD_TS_18661_3__ 2 +#define __FLT_HAS_DENORM__ 1 +#define __FLT_HAS_INFINITY__ 1 +#define __FLT_HAS_QUIET_NAN__ 1 +#define __FLT_IS_IEC_60559__ 1 +#define __FLT_MANT_DIG__ 24 +#define __FLT_MAX_10_EXP__ 38 +#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F +#define __FLT_MAX_EXP__ 128 +#define __FLT_MIN_10_EXP__ (-37) +#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F +#define __FLT_MIN_EXP__ (-125) +#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F +#define __FLT_RADIX__ 2 +#define __LDBL_DECIMAL_DIG__ 21 +#define __LDBL_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951L +#define __LDBL_DIG__ 18 +#define __LDBL_EPSILON__ 1.08420217248550443400745280086994171e-19L +#define __LDBL_HAS_DENORM__ 1 +#define __LDBL_HAS_INFINITY__ 1 +#define __LDBL_HAS_QUIET_NAN__ 1 +#define __LDBL_IS_IEC_60559__ 1 +#define __LDBL_MANT_DIG__ 64 +#define __LDBL_MAX_10_EXP__ 4932 +#define __LDBL_MAX__ 1.18973149535723176502126385303097021e+4932L +#define __LDBL_MAX_EXP__ 16384 +#define __LDBL_MIN_10_EXP__ (-4931) +#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L +#define __LDBL_MIN_EXP__ (-16381) +#define __LDBL_NORM_MAX__ 1.18973149535723176502126385303097021e+4932L + +#include_next "stdc-predef.h" diff --git a/wrapperhelper/include-override/x86_64/stdc-predef.h b/wrapperhelper/include-override/x86_64/stdc-predef.h index 5ed6af02d..5c1e4feed 100644 --- a/wrapperhelper/include-override/x86_64/stdc-predef.h +++ b/wrapperhelper/include-override/x86_64/stdc-predef.h @@ -68,7 +68,7 @@ #define __SSE_MATH__ 1 #define __SSE2__ 1 #define __SSE2_MATH__ 1 -#define __SSP_STRONG__ 3 +#define __SSP_STRONG__ 3 #define __amd64__ 1 #define __amd64 1 #define __code_model_small__ 1 @@ -109,16 +109,16 @@ //#define __BITINT_MAXWIDTH__ 65535 //#define __CHAR16_TYPE__ short unsigned int //#define __CHAR32_TYPE__ unsigned int -#define __INT8_C(c) c +//#define __INT8_C(c) c #define __INT8_MAX__ 0x7f //#define __INT8_TYPE__ signed char -#define __INT16_C(c) c +//#define __INT16_C(c) c #define __INT16_MAX__ 0x7fff //#define __INT16_TYPE__ short int -#define __INT32_C(c) c +//#define __INT32_C(c) c #define __INT32_MAX__ 0x7fffffff //#define __INT32_TYPE__ int -#define __INT64_C(c) c ## L +//#define __INT64_C(c) c ## L #define __INT64_MAX__ 0x7fffffffffffffffL //#define __INT64_TYPE__ long int #define __INT_FAST8_MAX__ 0x7f diff --git a/wrapperhelper/src/generator.c b/wrapperhelper/src/generator.c index cf4d18510..a4762c5eb 100644 --- a/wrapperhelper/src/generator.c +++ b/wrapperhelper/src/generator.c @@ -1,6 +1,7 @@ #include "generator.h" #include "lang.h" +#include "log.h" #include "prepare.h" static const char *rft2str[8] = { @@ -23,13 +24,14 @@ void request_print(const request_t *req) { case RQT_FUN_MY: case RQT_FUN_D: if (req->def.fun.typ) { - printf(" function%s %s%s%s", + printf(" function%s%s %s%s%s", rft2str[req->def.rty], + req->def.fun.needs_S ? " (with S)" : "", string_content(req->def.fun.typ), req->def.fun.fun2 ? " -> " : "", req->def.fun.fun2 ? string_content(req->def.fun.fun2) : ""); } else { - printf(" untyped function%s", rft2str[req->def.rty]); + printf(" untyped function%s%s", rft2str[req->def.rty], req->def.fun.needs_S ? " (with S)" : ""); } break; case RQT_DATA: @@ -50,13 +52,14 @@ void request_print(const request_t *req) { case RQT_FUN_MY: case RQT_FUN_D: if (req->val.fun.typ) { - printf(" function%s %s%s%s", + printf(" function%s%s %s%s%s", rft2str[req->val.rty], + req->val.fun.needs_S ? " (with S)" : "", string_content(req->val.fun.typ), req->val.fun.fun2 ? " -> " : "", req->val.fun.fun2 ? string_content(req->val.fun.fun2) : ""); } else { - printf(" untyped function%s", rft2str[req->val.rty]); + printf(" untyped function%s%s", rft2str[req->val.rty], req->val.fun.needs_S ? " (with S)" : ""); } break; case RQT_DATA: @@ -107,18 +110,20 @@ void request_print_check(const request_t *req) { && !strcmp(string_content(req->def.fun.typ) + 2, string_content(req->val.fun.typ) + 3); } if (!similar) { - printf("%s%s: function with %s%sdefault%s%s%s%s%s and dissimilar %ssolved%s%s%s%s%s\n", + printf("%s%s: function with %s%sdefault%s%s%s%s%s%s and dissimilar %ssolved%s%s%s%s%s%s\n", string_content(req->obj_name), req->weak ? " (weak)" : "", req->default_comment ? "commented " : "", req->def.fun.typ ? "" : "untyped ", rft2str[req->def.rty], + req->def.fun.needs_S ? " (with S)" : "", req->def.fun.typ ? " " : "", string_content(req->def.fun.typ), req->def.fun.fun2 ? " -> " : "", req->def.fun.fun2 ? string_content(req->def.fun.fun2) : "", req->val.fun.typ ? "" : "untyped ", rft2str[req->val.rty], + req->val.fun.needs_S ? " (with S)" : "", req->val.fun.typ ? " " : "", string_content(req->val.fun.typ), req->val.fun.fun2 ? " -> " : "", @@ -225,11 +230,16 @@ static void request_output(FILE *f, const request_t *req) { if (!req->has_val) { if (IS_RQT_FUNCTION(req->def.rty)) { if (!req->def.fun.typ) { - fprintf(f, "//GO%s%s(%s, \n", req->weak ? "W" : "", rqt_suffix[req->def.rty], string_content(req->obj_name)); + fprintf(f, "//GO%s%s%s(%s, \n", + req->weak ? "W" : "", + req->def.fun.needs_S ? "S" : "", + rqt_suffix[req->def.rty], + string_content(req->obj_name)); } else { - fprintf(f, "%sGO%s%s(%s, %s%s%s%s%s)%s\n", + fprintf(f, "%sGO%s%s%s(%s, %s%s%s%s%s)%s\n", req->default_comment ? "//" : "", req->weak ? "W" : "", + req->def.fun.needs_S ? "S" : "", rqt_suffix[req->def.rty], string_content(req->obj_name), valid_reqtype(req->def.fun.typ) ? "" : "\"", @@ -260,9 +270,10 @@ static void request_output(FILE *f, const request_t *req) { int is_comment = (IS_RQT_FUNCTION(req->def.rty) && req->def.fun.typ && !req->default_comment) ? (req->val.rty != req->def.rty) : (req->val.rty != RQT_FUN); - fprintf(f, "%sGO%s%s(%s, %s%s%s)\n", + fprintf(f, "%sGO%s%s%s(%s, %s%s%s)\n", is_comment ? "//" : "", req->weak ? "W" : "", + req->val.fun.needs_S ? "S" : "", rqt_suffix[req->val.rty], string_content(req->obj_name), string_content(req->val.fun.typ), @@ -321,12 +332,13 @@ VECTOR_IMPL(references, reference_del) VECTOR(references) *references_from_file(const char *filename, FILE *f) { prepare_t *prep = prepare_new_file(f, filename); if (!prep) { - printf("Failed to create the prepare structure for the reference file\n"); + log_memory("failed to create the prepare structure for the reference file\n"); return NULL; } VECTOR(references) *ret = vector_new(references); if (!ret) { + log_memory("failed to create a new reference vector\n"); prepare_del(prep); return NULL; } @@ -346,37 +358,37 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { int if_depth = 0, entered_depth = 0; string_t *line = string_new(); if (!line) { - printf("Error: failed to allocate new string for new reference line\n"); + log_memory("failed to allocate new string for new reference line\n"); } #define ADD_CHAR(c, has_destr, what) \ - if (!string_add_char(line, c)) { \ - printf("Error: failed to add " what "\n"); \ - if (has_destr) preproc_token_del(&tok); \ - goto failed; \ + if (!string_add_char(line, c)) { \ + log_memory("failed to add " what "\n"); \ + if (has_destr) preproc_token_del(&tok); \ + goto failed; \ } #define ADD_CSTR(cstr, has_destr, what) \ - if (!string_add_cstr(line, cstr)) { \ - printf("Error: failed to add " what "\n"); \ - if (has_destr) preproc_token_del(&tok); \ - goto failed; \ + if (!string_add_cstr(line, cstr)) { \ + log_memory("failed to add " what "\n"); \ + if (has_destr) preproc_token_del(&tok); \ + goto failed; \ } #define ADD_STR(str, has_destr, what) \ - if (!string_add_string(line, str)) { \ - printf("Error: failed to add " what "\n"); \ - if (has_destr) preproc_token_del(&tok); \ - goto failed; \ + if (!string_add_string(line, str)) { \ + log_memory("failed to add " what "\n"); \ + if (has_destr) preproc_token_del(&tok); \ + goto failed; \ } #define PUSH_LINE(has_destr) \ string_trim(line); \ if (!vector_push(references, ret, ((reference_t){.typ = REF_LINE, .line = line}))) { \ - printf("Error: failed to memorize reference line %d\n", lineno); \ + log_memory("failed to memorize reference line %d\n", lineno); \ if (has_destr) preproc_token_del(&tok); \ goto failed; \ } \ line = string_new(); \ if (!line) { \ - printf("Error: failed to allocate new string for new reference line\n"); \ + log_memory("failed to allocate new string for new reference line\n"); \ } while (1) { @@ -397,7 +409,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { string_clear(line); tok = pre_next_token(prep, 0); if (tok.tokt != PPTOK_IDENT) { - printf("Error: invalid reference file: invalid preprocessor line\n"); + log_error(&tok.loginfo, "invalid reference file: invalid preprocessor line\n"); preproc_token_del(&tok); goto failed; } @@ -405,13 +417,13 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { string_del(tok.tokv.str); tok = pre_next_token(prep, 0); if (tok.tokt != PPTOK_IDENT) { - printf("Error: invalid reference file: invalid '#ifdef' line\n"); + log_error(&tok.loginfo, "invalid reference file: invalid '#ifdef' line\n"); preproc_token_del(&tok); goto failed; } ++if_depth; if (!vector_push(references, ret, ((reference_t){.typ = REF_IFDEF, .line = tok.tokv.str}))) { - printf("Error: failed to memorize reference line %d\n", lineno); + log_error(&tok.loginfo, "failed to memorize reference line %d\n", lineno); string_del(tok.tokv.str); goto failed; } @@ -420,14 +432,14 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { string_del(tok.tokv.str); tok = pre_next_token(prep, 0); if (tok.tokt != PPTOK_IDENT) { - printf("Error: invalid reference file: invalid '#ifndef' line\n"); + log_error(&tok.loginfo, "invalid reference file: invalid '#ifndef' line\n"); preproc_token_del(&tok); goto failed; } if (if_depth == entered_depth) ++entered_depth; ++if_depth; if (!vector_push(references, ret, ((reference_t){.typ = REF_IFNDEF, .line = tok.tokv.str}))) { - printf("Error: failed to memorize reference line %d\n", lineno); + log_error(&tok.loginfo, "failed to memorize reference line %d\n", lineno); string_del(tok.tokv.str); goto failed; } @@ -438,7 +450,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { if (if_depth == entered_depth + 1) ++entered_depth; else if (if_depth == entered_depth) --entered_depth; if (!vector_push(references, ret, ((reference_t){.typ = REF_ELSE}))) { - printf("Error: failed to memorize reference line %d\n", lineno); + log_error(&tok.loginfo, "failed to memorize reference line %d\n", lineno); goto failed; } } else if (!strcmp(string_content(tok.tokv.str), "endif")) { @@ -447,11 +459,11 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { if (if_depth == entered_depth) --entered_depth; --if_depth; if (!vector_push(references, ret, ((reference_t){.typ = REF_ENDIF}))) { - printf("Error: failed to memorize reference line %d\n", lineno); + log_error(&tok.loginfo, "failed to memorize reference line %d\n", lineno); goto failed; } } else { - printf("Error: invalid reference file: invalid preprocessor command '%s'\n", string_content(tok.tokv.str)); + log_error(&tok.loginfo, "invalid reference file: invalid preprocessor command '%s'\n", string_content(tok.tokv.str)); string_del(tok.tokv.str); goto failed; } @@ -477,10 +489,12 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { || !strcmp(string_content(tok.tokv.str), "GO2") || !strcmp(string_content(tok.tokv.str), "GOD") || !strcmp(string_content(tok.tokv.str), "GOM") + || !strcmp(string_content(tok.tokv.str), "GOS") || !strcmp(string_content(tok.tokv.str), "GOW") || !strcmp(string_content(tok.tokv.str), "GOW2") || !strcmp(string_content(tok.tokv.str), "GOWD") - || !strcmp(string_content(tok.tokv.str), "GOWM"))) { + || !strcmp(string_content(tok.tokv.str), "GOWM") + || !strcmp(string_content(tok.tokv.str), "GOWS"))) { string_clear(line); if (is_comment) prepare_mark_nocomment(prep); int isweak = (string_content(tok.tokv.str)[2] == 'W'); @@ -495,21 +509,23 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { (string_content(tok.tokv.str)[isweak ? 3 : 2] == '2') ? RQT_FUN_2 : (string_content(tok.tokv.str)[isweak ? 3 : 2] == 'D') ? RQT_FUN_D : (string_content(tok.tokv.str)[isweak ? 3 : 2] == 'M') ? RQT_FUN_MY : RQT_FUN, + .fun.needs_S = (string_content(tok.tokv.str)[isweak ? 3 : 2] == 'S'), .fun.typ = NULL, .fun.fun2 = NULL, }, + .val = {0}, }; string_del(tok.tokv.str); tok = pre_next_token(prep, 0); if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_LPAREN)) { - printf("Error: invalid reference file: invalid GO line %d (lparen)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid GO line %d (lparen)\n", lineno); preproc_token_del(&tok); goto failed; } // Empty destructor tok = pre_next_token(prep, 0); if (tok.tokt != PPTOK_IDENT) { - printf("Error: invalid reference file: invalid GO line %d (obj_name)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid GO line %d (obj_name)\n", lineno); preproc_token_del(&tok); goto failed; } @@ -517,7 +533,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { // Token moved tok = pre_next_token(prep, 0); if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_COMMA)) { - printf("Error: invalid reference file: invalid GO line %d (comma)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid GO line %d (comma)\n", lineno); string_del(req.obj_name); preproc_token_del(&tok); goto failed; @@ -530,7 +546,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { tok = pre_next_token(prep, 0); if ((req.def.rty == RQT_FUN_2) || (req.def.rty == RQT_FUN_D)) { if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_COMMA)) { - printf("Error: invalid reference file: invalid GO line %d (comma 2)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid GO line %d (comma 2)\n", lineno); string_del(req.obj_name); string_del(req.def.fun.typ); preproc_token_del(&tok); @@ -539,7 +555,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { // Empty destructor tok = pre_next_token(prep, 0); if (tok.tokt != PPTOK_IDENT) { - printf("Error: invalid reference file: invalid GO line %d (redirect)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid GO line %d (redirect)\n", lineno); string_del(req.obj_name); string_del(req.def.fun.typ); preproc_token_del(&tok); @@ -550,7 +566,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { tok = pre_next_token(prep, 0); } if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_RPAREN)) { - printf("Error: invalid reference file: invalid GO line %d (rparen)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid GO line %d (rparen)\n", lineno); string_del(req.obj_name); string_del(req.def.fun.typ); if (req.def.fun.fun2) string_del(req.def.fun.fun2); @@ -561,7 +577,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { tok = pre_next_token(prep, 0); } if (tok.tokt != PPTOK_NEWLINE) { - printf("Error: invalid reference file: invalid GO line %d (newline)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid GO line %d (newline)\n", lineno); string_del(req.obj_name); if (req.def.fun.typ) string_del(req.def.fun.typ); if (req.def.fun.fun2) string_del(req.def.fun.fun2); @@ -569,7 +585,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { goto failed; } if (!vector_push(references, ret, ((reference_t){.typ = REF_REQ, .req = req}))) { - printf("Error: failed to add reference for %s\n", string_content(req.obj_name)); + log_memory("failed to add reference for %s\n", string_content(req.obj_name)); string_del(req.obj_name); if (req.def.fun.typ) string_del(req.def.fun.typ); if (req.def.fun.fun2) string_del(req.def.fun.fun2); @@ -598,18 +614,19 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { .dat.has_size = 0, .dat.sz = 0, }, + .val = {0}, }; string_del(tok.tokv.str); tok = pre_next_token(prep, 0); if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_LPAREN)) { - printf("Error: invalid reference file: invalid DATA line %d (lparen)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid DATA line %d (lparen)\n", lineno); preproc_token_del(&tok); goto failed; } // Empty destructor tok = pre_next_token(prep, 0); if (tok.tokt != PPTOK_IDENT) { - printf("Error: invalid reference file: invalid DATA line %d (obj_name)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid DATA line %d (obj_name)\n", lineno); preproc_token_del(&tok); goto failed; } @@ -617,7 +634,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { // Token moved tok = pre_next_token(prep, 0); if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_COMMA)) { - printf("Error: invalid reference file: invalid DATA line %d (comma)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid DATA line %d (comma)\n", lineno); string_del(req.obj_name); preproc_token_del(&tok); goto failed; @@ -627,8 +644,8 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { if (tok.tokt == PPTOK_NUM) { num_constant_t cst; // Assume target is 64 bits (box64) - if (!num_constant_convert(tok.tokv.str, &cst, 0)) { - printf("Error: invalid reference file: invalid DATA line %d (num conversion)\n", lineno); + if (!num_constant_convert(&tok.loginfo, tok.tokv.str, &cst, 0)) { + log_error(&tok.loginfo, "invalid reference file: invalid DATA line %d (num conversion)\n", lineno); string_del(req.obj_name); preproc_token_del(&tok); goto failed; @@ -637,7 +654,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { case NCT_FLOAT: case NCT_DOUBLE: case NCT_LDOUBLE: - printf("Error: invalid reference file: invalid DATA line %d (num conversion)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid DATA line %d (num conversion)\n", lineno); string_del(req.obj_name); string_del(tok.tokv.str); goto failed; @@ -650,7 +667,7 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { string_del(tok.tokv.str); // Delete token tok = pre_next_token(prep, 0); if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_RPAREN)) { - printf("Error: invalid reference file: invalid DATA line %d (rparen)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid DATA line %d (rparen)\n", lineno); string_del(req.obj_name); preproc_token_del(&tok); goto failed; @@ -659,13 +676,13 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { tok = pre_next_token(prep, 0); } if (tok.tokt != PPTOK_NEWLINE) { - printf("Error: invalid reference file: invalid DATA line %d (newline)\n", lineno); + log_error(&tok.loginfo, "invalid reference file: invalid DATA line %d (newline)\n", lineno); string_del(req.obj_name); preproc_token_del(&tok); goto failed; } if (!vector_push(references, ret, ((reference_t){.typ = REF_REQ, .req = req}))) { - printf("Error: failed to add reference for %s\n", string_content(req.obj_name)); + log_memory("failed to add reference for %s\n", string_content(req.obj_name)); request_del(&req); // Empty destructor goto failed; @@ -678,18 +695,18 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { } else if (tok.tokt == PPTOK_BLANK) { ADD_CHAR(tok.tokv.c, 0, "comment content") } else { - printf("Error: unknown token type in comment %u\n", tok.tokt); + log_error(&tok.loginfo, "unknown token type in comment %u\n", tok.tokt); preproc_token_del(&tok); goto failed; } if (!pre_next_newline_token(prep, line)) { - printf("Error: failed to add comment content\n"); + log_memory("failed to add comment content\n"); goto failed; } PUSH_LINE(0) ++lineno; } else { - printf("Error: invalid reference file: invalid token:\n"); + log_error(&tok.loginfo, "invalid reference file: invalid token:\n"); preproc_token_print(&tok); preproc_token_del(&tok); goto failed; @@ -708,7 +725,8 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) { return ret; } -static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map) { +// Simple versions (in practice, only use x86_64 and aarch64 as emu/target pair) +static int is_simple_type_ptr_to_simple(type_t *typ, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map) { if (typ->converted) { // printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name)); *needs_my = 1; @@ -721,7 +739,7 @@ static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my, khash return 1; // Assume pointers to builtin are simple case TYPE_ARRAY: if (typ->val.array.array_sz == (size_t)-1) return 0; // VLA are not simple - return is_simple_type_ptr_to(typ->val.array.typ, needs_D, needs_my, conv_map); + return is_simple_type_ptr_to_simple(typ->val.array.typ, needs_D, needs_my, conv_map); case TYPE_STRUCT_UNION: if (typ->_internal_use) return 1; // Recursive structures are OK as long as every other members are OK if (!typ->val.st->is_defined) return 1; // Undefined structures are OK since they are opaque @@ -729,7 +747,7 @@ static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my, khash typ->_internal_use = 1; for (size_t i = 0; i < typ->val.st->nmembers; ++i) { st_member_t *mem = &typ->val.st->members[i]; - if (!is_simple_type_ptr_to(mem->typ, needs_D, needs_my, conv_map)) { + if (!is_simple_type_ptr_to_simple(mem->typ, needs_D, needs_my, conv_map)) { typ->_internal_use = 0; return 0; } @@ -737,18 +755,18 @@ static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my, khash typ->_internal_use = 0; return 1; case TYPE_ENUM: - return is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my, conv_map); + return is_simple_type_ptr_to_simple(typ->val.typ, needs_D, needs_my, conv_map); case TYPE_PTR: - return is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my, conv_map); + return is_simple_type_ptr_to_simple(typ->val.typ, needs_D, needs_my, conv_map); case TYPE_FUNCTION: *needs_my = 1; return 1; default: - printf("Error: is_simple_type_ptr_to on unknown type %u\n", typ->typ); + printf("Error: is_simple_type_ptr_to_simple on unknown type %u\n", typ->typ); return 0; } } -static int is_simple_type(type_t *typ, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map) { +static int is_simple_type_simple(type_t *typ, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map) { if (typ->converted) { // printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name)); *needs_my = 1; @@ -763,7 +781,7 @@ static int is_simple_type(type_t *typ, int *needs_D, int *needs_my, khash_t(conv && (typ->val.builtin != BTT_IFLOAT128); // Assume builtin are simple except for __float128 case TYPE_ARRAY: if (typ->val.array.array_sz == (size_t)-1) return 0; // VLA are not simple - return is_simple_type_ptr_to(typ->val.array.typ, needs_D, needs_my, conv_map); + return is_simple_type_ptr_to_simple(typ->val.array.typ, needs_D, needs_my, conv_map); case TYPE_STRUCT_UNION: if (typ->_internal_use) return 1; // Recursive structures are OK as long as every other members are OK // if (!typ->val.st->is_defined) return 1; // Undefined structures are OK since they are opaque @@ -772,7 +790,7 @@ static int is_simple_type(type_t *typ, int *needs_D, int *needs_my, khash_t(conv typ->_internal_use = 1; for (size_t i = 0; i < typ->val.st->nmembers; ++i) { st_member_t *mem = &typ->val.st->members[i]; - if (!is_simple_type(mem->typ, needs_D, needs_my, conv_map)) { + if (!is_simple_type_simple(mem->typ, needs_D, needs_my, conv_map)) { typ->_internal_use = 0; return 0; } @@ -780,27 +798,28 @@ static int is_simple_type(type_t *typ, int *needs_D, int *needs_my, khash_t(conv typ->_internal_use = 0; return 1; case TYPE_ENUM: - return is_simple_type(typ->val.typ, needs_D, needs_my, conv_map); + return is_simple_type_simple(typ->val.typ, needs_D, needs_my, conv_map); case TYPE_PTR: - return is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my, conv_map); + return is_simple_type_ptr_to_simple(typ->val.typ, needs_D, needs_my, conv_map); case TYPE_FUNCTION: // Functions should be handled differently (GO instead of DATA) return 0; default: - printf("Error: is_simple_type on unknown type %u\n", typ->typ); + printf("Error: is_simple_type_simple on unknown type %u\n", typ->typ); return 0; } } -static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map, string_t *obj_name) { - if (typ->converted) { - if (!string_add_string(dest, typ->converted)) { +static int convert_type_simple(string_t *dest, type_t *emu_typ, type_t *target_typ, + int is_ret, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map, string_t *obj_name) { + if (emu_typ->converted) { + if (!string_add_string(dest, emu_typ->converted)) { printf("Error: failed to add explicit type conversion\n"); return 0; } return 1; } - khiter_t it = kh_get(conv_map, conv_map, typ); + khiter_t it = kh_get(conv_map, conv_map, emu_typ); if (it != kh_end(conv_map)) { if (!string_add_string(dest, kh_val(conv_map, it))) { printf("Error: failed to add explicit type conversion\n"); @@ -808,15 +827,19 @@ static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, i } return 1; } - if (typ->is_atomic) { - printf("TODO: convert_type for atomic types\n"); + if ((emu_typ->is_atomic) || (target_typ->is_atomic)) { + printf("Error: TODO: convert_type_simple for atomic types\n"); return 0; } - switch (typ->typ) { + if (emu_typ->typ != target_typ->typ) { + printf("Error: %s: %s type is different between emulated and target\n", string_content(obj_name), is_ret ? "return" : "argument"); + *needs_my = 1; + } + switch (emu_typ->typ) { case TYPE_BUILTIN: { int has_char = 0; char c; - switch (typ->val.builtin) { + switch (emu_typ->val.builtin) { case BTT_VOID: has_char = 1; c = 'v'; break; case BTT_BOOL: has_char = 1; c = 'i'; break; case BTT_CHAR: has_char = 1; c = 'c'; break; @@ -854,40 +877,40 @@ static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, i case BTT_LONGDOUBLE: *needs_D = 1; has_char = 1; c = 'D'; break; case BTT_CLONGDOUBLE: *needs_D = 1; has_char = 1; c = 'Y'; break; case BTT_ILONGDOUBLE: *needs_D = 1; has_char = 1; c = 'D'; break; - case BTT_FLOAT128: printf("Error: TODO: %s\n", builtin2str[typ->val.builtin]); has_char = 0; break; - case BTT_CFLOAT128: printf("Error: TODO: %s\n", builtin2str[typ->val.builtin]); has_char = 0; break; - case BTT_IFLOAT128: printf("Error: TODO: %s\n", builtin2str[typ->val.builtin]); has_char = 0; break; + case BTT_FLOAT128: printf("Error: TODO: %s\n", builtin2str[emu_typ->val.builtin]); return 0; + case BTT_CFLOAT128: printf("Error: TODO: %s\n", builtin2str[emu_typ->val.builtin]); return 0; + case BTT_IFLOAT128: printf("Error: TODO: %s\n", builtin2str[emu_typ->val.builtin]); return 0; case BTT_VA_LIST: *needs_my = 1; has_char = 1; c = 'A'; break; default: - printf("Error: convert_type on unknown builtin %u\n", typ->val.builtin); + printf("Error: convert_type_simple on unknown builtin %u\n", emu_typ->val.builtin); return 0; } if (has_char) { if (!string_add_char(dest, c)) { - printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]); + printf("Error: failed to add type char for %s\n", builtin2str[emu_typ->val.builtin]); return 0; } return 1; } else { - printf("Internal error: unknown state builtin=%u\n", typ->val.builtin); + printf("Internal error: unknown state builtin=%u\n", emu_typ->val.builtin); return 0; } } case TYPE_ARRAY: - printf("Error: convert_type on raw array\n"); + printf("Error: convert_type_simple on raw array\n"); return 0; case TYPE_STRUCT_UNION: - if (!typ->is_validated || typ->is_incomplete) { - printf("Error: incomplete return type for %s\n", string_content(obj_name)); + if (!emu_typ->is_validated || emu_typ->is_incomplete) { + printf("Error: incomplete structure for %s\n", string_content(obj_name)); return 0; } if (is_ret) { - if (typ->szinfo.size <= 8) { + if (emu_typ->szinfo.size <= 8) { if (!string_add_char(dest, 'U')) { printf("Error: failed to add type char for structure return\n"); return 0; } return 1; - } else if (typ->szinfo.size <= 16) { + } else if (emu_typ->szinfo.size <= 16) { if (!string_add_char(dest, 'H')) { printf("Error: failed to add type char for large structure return\n"); return 0; @@ -901,16 +924,21 @@ static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, i return 1; } } else { - if (typ->val.st->nmembers == 1) { - return convert_type(dest, typ->val.st->members[0].typ, is_ret, needs_D, needs_my, conv_map, obj_name); + if ((emu_typ->val.st->nmembers == 1) && (target_typ->typ == TYPE_STRUCT_UNION) && (target_typ->val.st->nmembers == 1)) { + return convert_type_simple(dest, emu_typ->val.st->members[0].typ, target_typ->val.st->members[0].typ, is_ret, needs_D, needs_my, conv_map, obj_name); } - printf("TODO: convert_type on structure as argument (%s)\n", string_content(obj_name)); + printf("Error: TODO: convert_type_simple on structure as argument (%s)\n", string_content(obj_name)); return 0; } case TYPE_ENUM: - return convert_type(dest, typ->val.typ, is_ret, needs_D, needs_my, conv_map, obj_name); + if (target_typ->typ == TYPE_ENUM) { + return convert_type_simple(dest, emu_typ->val.typ, target_typ->val.typ, is_ret, needs_D, needs_my, conv_map, obj_name); + } else { + printf("Fatal: convert_type_simple(enum, non-enum)\n"); + return 0; + } case TYPE_PTR: - if (is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my, conv_map)) { + if (is_simple_type_ptr_to_simple(emu_typ->val.typ, needs_D, needs_my, conv_map)) { if (!string_add_char(dest, 'p')) { printf("Error: failed to add type char for simple pointer\n"); return 0; @@ -919,34 +947,35 @@ static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, i } else { *needs_my = 1; if (!string_add_char(dest, 'p')) { - printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]); + printf("Error: failed to add type char for complex pointer\n"); return 0; } return 1; } case TYPE_FUNCTION: - printf("Error: convert_type on raw function\n"); + printf("Error: convert_type_simple on raw function\n"); return 0; default: - printf("Error: convert_type on unknown type %u\n", typ->typ); + printf("Error: convert_type_simple on unknown type %u\n", emu_typ->typ); return 0; } } -static int convert_type_post(string_t *dest, type_t *typ, string_t *obj_name) { - if (typ->converted) return 1; - if (typ->is_atomic) { - printf("TODO: convert_type_post for atomic types\n"); +static int convert_type_post_simple(string_t *dest, type_t *emu_typ, type_t *target_typ, string_t *obj_name) { + if (emu_typ->converted) return 1; + if (emu_typ->is_atomic) { + printf("Error: TODO: convert_type_post_simple for atomic types\n"); return 0; } - switch (typ->typ) { + (void)target_typ; + switch (emu_typ->typ) { case TYPE_BUILTIN: return 1; case TYPE_ARRAY: return 1; case TYPE_STRUCT_UNION: - if (!typ->is_validated || typ->is_incomplete) { - printf("Error: incomplete return type for %s\n", string_content(obj_name)); + if (!emu_typ->is_validated || emu_typ->is_incomplete) { + printf("Error: incomplete structure for %s\n", string_content(obj_name)); return 0; } - if (typ->szinfo.size <= 16) { + if (emu_typ->szinfo.size <= 16) { return 1; } else { if (!string_add_char(dest, 'p')) { @@ -958,15 +987,674 @@ static int convert_type_post(string_t *dest, type_t *typ, string_t *obj_name) { case TYPE_ENUM: return 1; case TYPE_PTR: return 1; case TYPE_FUNCTION: return 1; + } + printf("Error: convert_type_post_simple on unknown type %u\n", emu_typ->typ); + return 0; +} + +int solve_request_simple(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(conv_map) *conv_map) { + if (emu_typ->typ != target_typ->typ) { + printf("Error: %s: emulated and target types are different (emulated is %u, target is %u)\n", + string_content(req->obj_name), emu_typ->typ, target_typ->typ); + return 0; + } + if (emu_typ->typ == TYPE_FUNCTION) { + int needs_D = 0, needs_my = req->def.fun.typ && (req->def.rty == RQT_FUN_MY), needs_2 = 0; + int convert_post; + size_t idx_conv; + req->val.fun.typ = string_new(); + if (!req->val.fun.typ) { + printf("Error: failed to create function type string\n"); + return 0; + } + if (!convert_type_simple(req->val.fun.typ, emu_typ->val.fun.ret, target_typ->val.fun.ret, 1, &needs_D, &needs_my, conv_map, req->obj_name)) + goto fun_fail; + idx_conv = string_len(req->val.fun.typ); + if (!string_add_char(req->val.fun.typ, 'F')) { + printf("Error: failed to add convention char\n"); + goto fun_fail; + } + convert_post = convert_type_post_simple(req->val.fun.typ, emu_typ->val.fun.ret, target_typ->val.fun.ret, req->obj_name); + if (!convert_post) goto fun_fail; + if (emu_typ->val.fun.nargs == (size_t)-1) { + printf("Warning: %s: assuming empty specification is void specification\n", string_content(req->obj_name)); + if (convert_post == 1) { + if (!string_add_char(req->val.fun.typ, 'v')) { + printf("Error: failed to add void specification char\n"); + goto fun_fail; + } + } + } else if (!emu_typ->val.fun.nargs && !emu_typ->val.fun.has_varargs) { + if (convert_post == 1) { + if (!string_add_char(req->val.fun.typ, 'v')) { + printf("Error: failed to add void specification char\n"); + goto fun_fail; + } + } + } else { + for (size_t i = 0; i < emu_typ->val.fun.nargs; ++i) { + if (!convert_type_simple(req->val.fun.typ, emu_typ->val.fun.args[i], target_typ->val.fun.args[i], 0, &needs_D, &needs_my, conv_map, req->obj_name)) + goto fun_fail; + } + if (emu_typ->val.fun.has_varargs) { + if (req->def.fun.typ + && (string_len(req->def.fun.typ) == string_len(req->val.fun.typ) + 1) + && !strncmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ), string_len(req->val.fun.typ)) + && ((string_content(req->def.fun.typ)[string_len(req->val.fun.typ)] == 'M') + || (string_content(req->def.fun.typ)[string_len(req->val.fun.typ)] == 'N'))) { + if (!string_add_char(req->val.fun.typ, string_content(req->def.fun.typ)[string_len(req->val.fun.typ)])) { + printf("Error: failed to add type char '%c' for %s\n", + string_content(req->def.fun.typ)[string_len(req->val.fun.typ)], + builtin2str[emu_typ->val.builtin]); + goto fun_fail; + } + } else { + needs_my = 1; + if (!string_add_char(req->val.fun.typ, 'V')) { + printf("Error: failed to add type char 'V' for %s\n", builtin2str[emu_typ->val.builtin]); + goto fun_fail; + } + } + } + } + + // fun_succ: + // Add 'E' by default, unless we have the same function as before + if (needs_my && (req->default_comment + || (req->def.rty != RQT_FUN_MY) + || strcmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ)))) { + if (!string_add_char_at(req->val.fun.typ, 'E', idx_conv + 1)) { + printf("Error: failed to add emu char\n"); + goto fun_fail; + } + } + if (req->def.fun.typ && (req->def.rty == RQT_FUN_2) && !needs_my) { + needs_2 = 1; + req->val.fun.fun2 = string_dup(req->def.fun.fun2); + if (!req->val.fun.fun2) { + printf("Error: failed to duplicate string (request for function %s with default redirection)\n", string_content(req->obj_name)); + return 0; + } + } else if (req->def.fun.typ && (req->def.rty == RQT_FUN_D) && !needs_my) { + needs_2 = 0; + req->val.fun.fun2 = string_dup(req->def.fun.fun2); + if (!req->val.fun.fun2) { + printf("Error: failed to duplicate string (request for function %s with long double types)\n", string_content(req->obj_name)); + return 0; + } + } else if (!needs_my && needs_D) { + req->val.fun.fun2 = string_new(); + if (!req->val.fun.fun2) { + printf("Error: failed to create empty string (request for function %s with long double types)\n", string_content(req->obj_name)); + return 0; + } + } + req->val.rty = + needs_my ? RQT_FUN_MY : + needs_2 ? RQT_FUN_2 : + needs_D ? RQT_FUN_D : RQT_FUN; + req->has_val = 1; + return 1; + + fun_fail: + string_del(req->val.fun.typ); + return 0; + } else { + int needs_D = 0, needs_my = req->def.dat.has_size && (req->def.rty == RQT_DATAM); + if (is_simple_type_simple(emu_typ, &needs_D, &needs_my, conv_map)) { + // TODO: Hmm... + req->val.rty = needs_my ? RQT_DATAM : req->def.rty; + req->val.dat.has_size = 1; + req->val.dat.sz = emu_typ->szinfo.size; + req->has_val = 1; + return 1; + } else { + log_TODO_nopos("solve_request_simple for data %s with non-simple type ", string_content(req->obj_name)); + type_print(emu_typ); + printf("\n"); + return 0; + } + } +} +int solve_request_map_simple(request_t *req, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map) { + int hasemu = 0, hastarget = 0; + khiter_t emuit, targetit; + emuit = kh_get(decl_map, emu_decl_map, string_content(req->obj_name)); + if (emuit == kh_end(emu_decl_map)) { + goto failed; + } + if ((kh_val(emu_decl_map, emuit)->storage == STORAGE_STATIC) || (kh_val(emu_decl_map, emuit)->storage == STORAGE_TLS_STATIC)) { + goto failed; + } + targetit = kh_get(decl_map, target_decl_map, string_content(req->obj_name)); + if (targetit == kh_end(target_decl_map)) { + goto failed; + } + if ((kh_val(target_decl_map, targetit)->storage == STORAGE_STATIC) || (kh_val(target_decl_map, targetit)->storage == STORAGE_TLS_STATIC)) { + goto failed; + } + return solve_request_simple(req, kh_val(emu_decl_map, emuit)->typ, kh_val(target_decl_map, targetit)->typ, conv_map); + +failed: + if (string_content(req->obj_name)[0] != '_') { + if (!hasemu && !hastarget) { + printf("Error: %s was not declared in the emulated and target architectures\n", string_content(req->obj_name)); + } else if (!hasemu) { + printf("Error: %s was not declared only in the emulated architecture\n", string_content(req->obj_name)); + } else if (!hastarget) { + printf("Error: %s was not declared only in the target architecture\n", string_content(req->obj_name)); + } else { + printf("Error: internal error: failed but found for %s\n", string_content(req->obj_name)); + } + } + return 0; +} +int solve_references_simple(VECTOR(references) *refs, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map) { + int ret = 1; + int cond_depth = 0, ok_depth = 0; + vector_for(references, ref, refs) { + switch (ref->typ) { + case REF_REQ: + if (ok_depth == cond_depth) { + if (!solve_request_map_simple(&ref->req, emu_decl_map, target_decl_map, conv_map)) ret = 0; + } else { + ref->req.ignored = 1; + } + break; + case REF_LINE: + break; + case REF_IFDEF: + ++cond_depth; + break; + case REF_IFNDEF: + if (cond_depth == ok_depth) ++ok_depth; + ++cond_depth; + break; + case REF_ELSE: + if (cond_depth == ok_depth) --ok_depth; + else if (cond_depth == ok_depth + 1) ++ok_depth; + break; + case REF_ENDIF: + if (cond_depth == ok_depth) --ok_depth; + --cond_depth; + break; + } + } + return ret; +} + +// Complex versions +enum safeness_e { + SAFE_ABORT, // Failure + SAFE_OK, // Simple, can output 'p' + SAFE_EXPAND, // Complex but automatable, needs to output 'b..._' +}; +static enum safeness_e get_safeness_ptr(type_t *emu_typ, type_t *target_typ, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map, string_t *obj_name) { + if (emu_typ->typ != target_typ->typ) { + printf("Error: %s: pointer with different types between emu and target\n", string_content(obj_name)); + return SAFE_ABORT; + } + if (emu_typ->converted) { + printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name)); + *needs_my = 1; + return SAFE_OK; + } else if (kh_get(conv_map, conv_map, emu_typ) != kh_end(conv_map)) { + printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name)); + *needs_my = 1; + return SAFE_OK; + } + switch (emu_typ->typ) { + case TYPE_BUILTIN: + if (emu_typ->val.builtin != target_typ->val.builtin) { + // printf("Warning: %s: emu and target have pointers to different size type\n", string_content(obj_name)); + return SAFE_ABORT; + } + if (emu_typ->szinfo.size != target_typ->szinfo.size) { + // printf("Warning: %s: emu and target have pointers to different size type\n", string_content(obj_name)); + return SAFE_EXPAND; + } + /* if (emu_typ->szinfo.align != target_typ->szinfo.align) { + // printf("Warning: %s: emu and target have pointers to different alignment type\n", string_content(obj_name)); + return SAFE_EXPAND; + } */ + // Assume pointers to builtins of the same size and alignment are simple + return SAFE_OK; + case TYPE_ARRAY: + if (emu_typ->szinfo.size != target_typ->szinfo.size) { + // printf("Warning: %s: emu and target have pointers to arrays with different size type\n", string_content(obj_name)); + return SAFE_EXPAND; + } + if (emu_typ->szinfo.align != target_typ->szinfo.align) { + // printf("Warning: %s: emu and target have pointers to arrays with different alignment type\n", string_content(obj_name)); + return SAFE_EXPAND; + } + if (emu_typ->val.array.array_sz != target_typ->val.array.array_sz) { + printf("Error: %s: emu and target have arrays of different size\n", string_content(obj_name)); + return SAFE_ABORT; // Shouldn't happen + } + // Elements also have the same size + if ((emu_typ->val.array.array_sz == (size_t)-1) || (target_typ->val.array.array_sz == (size_t)-1)) { + printf("Error: %s: has variable length arrays\n", string_content(obj_name)); + return SAFE_ABORT; // VLA require manual intervention + } + return get_safeness_ptr(emu_typ->val.array.typ, target_typ->val.array.typ, needs_D, needs_my, conv_map, obj_name); + case TYPE_STRUCT_UNION: + if (emu_typ->val.st->is_struct != target_typ->val.st->is_struct) { + printf("Error: %s: incoherent struct/union type between emulated and target architectures for %s\n", + string_content(obj_name), emu_typ->val.st->tag ? string_content(emu_typ->val.st->tag) : ""); + return SAFE_ABORT; + } + if (emu_typ->is_incomplete != target_typ->is_incomplete) { + printf("Error: %s: incoherent struct/union completion type between emulated and target architectures for %s\n", + string_content(obj_name), emu_typ->val.st->tag ? string_content(emu_typ->val.st->tag) : ""); + return SAFE_ABORT; + } + if (emu_typ->is_incomplete) { + return SAFE_OK; // Undefined structures are OK since they are opaque + } + if (emu_typ->val.st->nmembers != target_typ->val.st->nmembers) { + printf("Error: %s: struct/union %s has different number of members between emulated and target architectures\n", + string_content(obj_name), emu_typ->val.st->tag ? string_content(emu_typ->val.st->tag) : ""); + return SAFE_ABORT; + } + if (emu_typ->val.st->has_self_recursion) { + // Self-reference implies manual intervention + *needs_my = 1; + return SAFE_OK; + } + if (emu_typ->val.st->nmembers == 1) { + // Assume structs and unions of one element has the same ABI as that element directly + return get_safeness_ptr(emu_typ->val.st->members[0].typ, target_typ->val.st->members[0].typ, needs_D, needs_my, conv_map, obj_name); + } + if (emu_typ->val.st->is_struct) { + // Structures are OK if all named members are OK and at the same memory offset + for (size_t i = 0; i < emu_typ->val.st->nmembers; ++i) { + st_member_t *emu_mem = &emu_typ->val.st->members[i]; + st_member_t *target_mem = &target_typ->val.st->members[i]; + if (emu_mem->name) { + if ((emu_mem->byte_offset != target_mem->byte_offset) || (emu_mem->bit_offset != target_mem->bit_offset)) { + return SAFE_EXPAND; + } + enum safeness_e saf = get_safeness_ptr(emu_mem->typ, target_mem->typ, needs_D, needs_my, conv_map, obj_name); + if (saf != SAFE_OK) return saf; + } + } + return SAFE_OK; + } else { + // Unions are OK if all named members are OK (memory offset is always 0) + for (size_t i = 0; i < emu_typ->val.st->nmembers; ++i) { + st_member_t *emu_mem = &emu_typ->val.st->members[i]; + st_member_t *target_mem = &target_typ->val.st->members[i]; + if (emu_mem->name) { + enum safeness_e saf = get_safeness_ptr(emu_mem->typ, target_mem->typ, needs_D, needs_my, conv_map, obj_name); + if (saf != SAFE_OK) return saf; + } + } + return SAFE_OK; + } + case TYPE_ENUM: + return get_safeness_ptr(emu_typ->val.typ, target_typ->val.typ, needs_D, needs_my, conv_map, obj_name); + case TYPE_PTR: + return SAFE_EXPAND; + case TYPE_FUNCTION: + *needs_my = 1; + return SAFE_OK; default: - printf("Error: convert_type_post on unknown type %u\n", typ->typ); + printf("Error: get_safeness_ptr on unknown type %u\n", emu_typ->typ); + return SAFE_ABORT; + } +} +static enum safeness_e get_safeness(type_t *emu_typ, type_t *target_typ, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map, string_t *obj_name) { + if (emu_typ->typ != target_typ->typ) { + printf("Error: %s: data with different types between emu and target\n", string_content(obj_name)); + return SAFE_ABORT; // Invalid type + } + if (emu_typ->converted) { + // printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name)); + *needs_my = 1; + return SAFE_OK; + } else if (kh_get(conv_map, conv_map, emu_typ) != kh_end(conv_map)) { + // printf("Warning: %s uses a converted type but is not the converted type\n", string_content(obj_name)); + *needs_my = 1; + return SAFE_OK; + } + switch (emu_typ->typ) { + case TYPE_BUILTIN: + if ((emu_typ->val.builtin != target_typ->val.builtin) + || (emu_typ->szinfo.size != target_typ->szinfo.size) + || (emu_typ->szinfo.align != target_typ->szinfo.align) + || (emu_typ->val.builtin == BTT_FLOAT128) + || (emu_typ->val.builtin == BTT_CFLOAT128) + || (emu_typ->val.builtin == BTT_IFLOAT128)) { + // Assume all builtins are simple except for __float128 and those with different size or alignment + *needs_my = 1; + } + return SAFE_OK; + case TYPE_ARRAY: + if (emu_typ->szinfo.size != target_typ->szinfo.size) { + // printf("Warning: %s: emu and target have pointers to different size type\n", string_content(obj_name)); + return SAFE_EXPAND; + } + if (emu_typ->szinfo.align != target_typ->szinfo.align) { + // printf("Warning: %s: emu and target have pointers to different alignment type\n", string_content(obj_name)); + return SAFE_EXPAND; + } + if (emu_typ->val.array.array_sz != target_typ->val.array.array_sz) { + printf("Error: %s: emu and target have arrays of different size\n", string_content(obj_name)); + return SAFE_ABORT; // Shouldn't happen + } + // Elements also have the same size + if ((emu_typ->val.array.array_sz == (size_t)-1) || (target_typ->val.array.array_sz == (size_t)-1)) { + printf("Error: %s: has variable length arrays\n", string_content(obj_name)); + return SAFE_ABORT; // VLA require manual intervention + } + return get_safeness_ptr(emu_typ->val.array.typ, target_typ->val.array.typ, needs_D, needs_my, conv_map, obj_name); + case TYPE_STRUCT_UNION: + if (emu_typ->val.st->is_struct != target_typ->val.st->is_struct) { + printf("Error: %s: incoherent struct/union type between emulated and target architectures for %s\n", + string_content(obj_name), emu_typ->val.st->tag ? string_content(emu_typ->val.st->tag) : ""); + return SAFE_ABORT; + } + if (emu_typ->is_incomplete != target_typ->is_incomplete) { + printf("Error: %s: incoherent struct/union completion type between emulated and target architectures for %s\n", + string_content(obj_name), emu_typ->val.st->tag ? string_content(emu_typ->val.st->tag) : ""); + return SAFE_ABORT; + } + if (emu_typ->is_incomplete) { + printf("Warning: %s: undefined struct/union %s considered as simple\n", + string_content(obj_name), emu_typ->val.st->tag ? string_content(emu_typ->val.st->tag) : ""); + return SAFE_OK; // Assume undefined structures are OK since they are opaque + } + if (emu_typ->val.st->nmembers != target_typ->val.st->nmembers) { + printf("Error: %s: struct/union %s has different number of members between emulated and target architectures\n", + string_content(obj_name), emu_typ->val.st->tag ? string_content(emu_typ->val.st->tag) : ""); + return SAFE_ABORT; + } + if (emu_typ->val.st->has_self_recursion) { + // Self-reference implies manual intervention + *needs_my = 1; + return SAFE_OK; + } + for (size_t i = 0; i < emu_typ->val.st->nmembers; ++i) { + switch (get_safeness(emu_typ->val.st->members[i].typ, target_typ->val.st->members[i].typ, needs_D, needs_my, conv_map, obj_name)) { + case SAFE_OK: break; + case SAFE_ABORT: + case SAFE_EXPAND: + default: return SAFE_ABORT; + } + } + return SAFE_OK; + case TYPE_ENUM: + return get_safeness(emu_typ->val.typ, target_typ->val.typ, needs_D, needs_my, conv_map, obj_name); + case TYPE_PTR: + // Pointers have different sizes here + return SAFE_EXPAND; + case TYPE_FUNCTION: + // Functions should be handled differently (GO instead of DATA) + return SAFE_ABORT; + default: + printf("Error: get_safeness on unknown type %u\n", emu_typ->typ); + return SAFE_ABORT; + } +} + +// needs_S != NULL iff type is return +static int convert_type(string_t *dest, type_t *emu_typ, type_t *target_typ, + _Bool *needs_S, int *needs_D, int *needs_my, khash_t(conv_map) *conv_map, string_t *obj_name) { + if (emu_typ->converted) { + if (!string_add_string(dest, emu_typ->converted)) { + printf("Error: failed to add explicit type conversion\n"); + return 0; + } + return 1; + } + khiter_t it = kh_get(conv_map, conv_map, emu_typ); + if (it != kh_end(conv_map)) { + if (!string_add_string(dest, kh_val(conv_map, it))) { + printf("Error: failed to add explicit type conversion\n"); + return 0; + } + return 1; + } + if ((emu_typ->is_atomic) || (target_typ->is_atomic)) { + printf("Error: TODO: convert_type for atomic types\n"); + return 0; + } + if (emu_typ->typ != target_typ->typ) { + printf("Error: %s: %s type is different between emulated and target\n", string_content(obj_name), needs_S ? "return" : "argument"); return 0; } + switch (emu_typ->typ) { + case TYPE_BUILTIN: { + int has_char = 0; + char c; + switch (emu_typ->val.builtin) { + case BTT_VOID: has_char = 1; c = 'v'; break; + case BTT_BOOL: has_char = 1; c = 'i'; break; + case BTT_CHAR: has_char = 1; c = 'c'; break; + case BTT_SCHAR: has_char = 1; c = 'c'; break; + case BTT_UCHAR: has_char = 1; c = 'C'; break; + case BTT_SHORT: has_char = 1; c = 'w'; break; + case BTT_SSHORT: has_char = 1; c = 'w'; break; + case BTT_USHORT: has_char = 1; c = 'W'; break; + case BTT_INT: has_char = 1; c = 'i'; break; + case BTT_SINT: has_char = 1; c = 'i'; break; + case BTT_UINT: has_char = 1; c = 'u'; break; + case BTT_LONG: has_char = 1; c = 'l'; break; + case BTT_SLONG: has_char = 1; c = 'l'; break; + case BTT_ULONG: has_char = 1; c = 'L'; break; + case BTT_LONGLONG: has_char = 1; c = 'I'; break; + case BTT_SLONGLONG: has_char = 1; c = 'I'; break; + case BTT_ULONGLONG: has_char = 1; c = 'U'; break; + case BTT_INT128: has_char = 1; c = 'H'; break; + case BTT_SINT128: has_char = 1; c = 'H'; break; + case BTT_UINT128: has_char = 1; c = 'H'; break; + case BTT_S8: has_char = 1; c = 'c'; break; + case BTT_U8: has_char = 1; c = 'C'; break; + case BTT_S16: has_char = 1; c = 'w'; break; + case BTT_U16: has_char = 1; c = 'W'; break; + case BTT_S32: has_char = 1; c = 'i'; break; + case BTT_U32: has_char = 1; c = 'u'; break; + case BTT_S64: has_char = 1; c = 'I'; break; + case BTT_U64: has_char = 1; c = 'U'; break; + case BTT_FLOAT: has_char = 1; c = 'f'; break; + case BTT_CFLOAT: has_char = 1; c = 'x'; break; + case BTT_IFLOAT: has_char = 1; c = 'f'; break; + case BTT_DOUBLE: has_char = 1; c = 'd'; break; + case BTT_CDOUBLE: has_char = 1; c = 'X'; break; + case BTT_IDOUBLE: has_char = 1; c = 'd'; break; + case BTT_LONGDOUBLE: *needs_D = 1; has_char = 1; c = 'D'; break; + case BTT_CLONGDOUBLE: *needs_D = 1; has_char = 1; c = 'Y'; break; + case BTT_ILONGDOUBLE: *needs_D = 1; has_char = 1; c = 'D'; break; + case BTT_FLOAT128: printf("Error: TODO: %s\n", builtin2str[emu_typ->val.builtin]); return 0; + case BTT_CFLOAT128: printf("Error: TODO: %s\n", builtin2str[emu_typ->val.builtin]); return 0; + case BTT_IFLOAT128: printf("Error: TODO: %s\n", builtin2str[emu_typ->val.builtin]); return 0; + case BTT_VA_LIST: *needs_my = 1; has_char = 1; c = 'p'; break; + default: + printf("Error: convert_type on unknown builtin %u\n", emu_typ->val.builtin); + return 0; + } + if (has_char) { + if (!string_add_char(dest, c)) { + printf("Error: failed to add type char for complex pointer\n"); + return 0; + } + return 1; + } else { + printf("Internal error: unknown state builtin=%u\n", emu_typ->val.builtin); + return 0; + } } + case TYPE_ARRAY: { + // May come from the content of a pointer or structure + if ((emu_typ->val.array.array_sz == (size_t)-1) || (target_typ->val.array.array_sz == (size_t)-1)) { + printf("Error: %s: has variable length arrays\n", string_content(obj_name)); + return 0; // VLA require manual intervention + } + if (emu_typ->val.array.array_sz != target_typ->val.array.array_sz) { + printf("Error: %s: emu and target have arrays of different size\n", string_content(obj_name)); + return 0; // Shouldn't happen + } + if (!emu_typ->val.array.array_sz) { + // printf("Warning: %s: has zero-length array\n", string_content(obj_name)); + return 1; + } + size_t idx = string_len(dest); + if (!convert_type(dest, emu_typ->val.array.typ, target_typ->val.array.typ, needs_S, needs_D, needs_my, conv_map, obj_name)) + return 0; + size_t end = string_len(dest); + if (idx == end) return 1; + if (!string_reserve(dest, idx + (end - idx) * emu_typ->val.array.array_sz)) { + printf("Error: failed to reserve string capacity (for array of type conversing length %zu and size %zu)\n", + end - idx, emu_typ->val.array.array_sz); + return 0; + } + for (size_t i = 1; i < emu_typ->val.array.array_sz; ++i) { + memcpy(string_content(dest) + idx + (end - idx) * i, string_content(dest) + idx, end - idx); + // HACKHACKHACK === + string_len(dest) += end - idx; + // === HACKHACKHACK + } + return 1; } + case TYPE_STRUCT_UNION: + if (!emu_typ->is_validated || emu_typ->is_incomplete) { + printf("Error: incomplete structure for %s\n", string_content(obj_name)); + return 0; + } + if (needs_S) { + *needs_S = 1; + // TODO: remove this and add support in the python wrappers for structure returns + if (!string_add_char(dest, 'p')) { + printf("Error: failed to add type char for very large structure return\n"); + return 0; + } + return 1; + } else { + if ((emu_typ->val.st->nmembers == 1) && (target_typ->typ == TYPE_STRUCT_UNION) && (target_typ->val.st->nmembers == 1)) { + return convert_type(dest, emu_typ->val.st->members[0].typ, target_typ->val.st->members[0].typ, needs_S, needs_D, needs_my, conv_map, obj_name); + } + printf("Error: TODO: convert_type on structure as argument (%s)\n", string_content(obj_name)); + return 0; + } + case TYPE_ENUM: + return convert_type(dest, emu_typ->val.typ, target_typ->val.typ, needs_S, needs_D, needs_my, conv_map, obj_name); + case TYPE_PTR: + switch (get_safeness_ptr(emu_typ->val.typ, target_typ->val.typ, needs_D, needs_my, conv_map, obj_name)) { + default: + printf("Internal error: %s: pointer to unknown type\n", string_content(obj_name)); + return 0; + + case SAFE_ABORT: + return 0; + + case SAFE_OK: + if (!string_add_char(dest, 'p')) { + printf("Error: failed to add type char for simple pointer\n"); + return 0; + } + return 1; + + case SAFE_EXPAND: + if (!string_add_char(dest, emu_typ->is_const ? 'r' : 'b')) { + printf("Error: failed to add start type char for wrapping pointer\n"); + return 0; + } + // Find the underlying type to convert + emu_typ = emu_typ->val.typ; + target_typ = target_typ->val.typ; + do_expanded: + switch (emu_typ->typ) { + case TYPE_BUILTIN: + if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) { + return 0; + } + break; + case TYPE_ARRAY: + if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) { + return 0; + } + break; + case TYPE_STRUCT_UNION: + if (!emu_typ->val.st->is_defined) { + printf("Internal error: EXPAND with undefined struct/union ptr\n"); + return 0; + } + if (emu_typ->val.st->nmembers == 1) { // Single-member struct/union + emu_typ = emu_typ->val.st->members[0].typ; + target_typ = target_typ->val.st->members[0].typ; + goto do_expanded; + } + for (size_t i = 0; i < emu_typ->val.st->nmembers; ++i) { + if (!convert_type(dest, emu_typ->val.st->members[i].typ, target_typ->val.st->members[i].typ, needs_S, needs_D, needs_my, conv_map, obj_name)) { + return 0; + } + } + break; + case TYPE_ENUM: + emu_typ = emu_typ->val.typ; + target_typ = target_typ->val.typ; + if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) { + return 0; + } + break; + case TYPE_PTR: + if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) { + return 0; + } + break; + case TYPE_FUNCTION: + if (!convert_type(dest, emu_typ, target_typ, needs_S, needs_D, needs_my, conv_map, obj_name)) { + return 0; + } + break; + } + if (!string_add_char(dest, '_')) { + printf("Error: failed to add end type char for wrapping pointer\n"); + return 0; + } + return 1; + } + case TYPE_FUNCTION: + printf("Internal error: convert_type on raw function\n"); + return 1; + default: + printf("Error: convert_type on unknown type %u\n", emu_typ->typ); + return 0; + } +} +// TODO: move this function to the python script (implement correct structure returns) +static int convert_type_post(string_t *dest, type_t *emu_typ, type_t *target_typ, string_t *obj_name) { + if (emu_typ->converted) return 1; + if (emu_typ->is_atomic) { + printf("Error: TODO: convert_type_post for atomic types\n"); + return 0; + } + (void)target_typ; + switch (emu_typ->typ) { + case TYPE_BUILTIN: return 1; + case TYPE_ARRAY: return 1; + case TYPE_STRUCT_UNION: + if (!emu_typ->is_validated || emu_typ->is_incomplete) { + printf("Error: incomplete structure for %s\n", string_content(obj_name)); + return 0; + } + // Hard coded + if (!string_add_char(dest, 'p')) { + printf("Error: failed to add type char for very large structure return as parameter\n"); + return 0; + } + return 2; + case TYPE_ENUM: return 1; + case TYPE_PTR: return 1; + case TYPE_FUNCTION: return 1; + } + printf("Error: convert_type_post on unknown type %u\n", emu_typ->typ); + return 0; } int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(conv_map) *conv_map) { - if (!type_t_equal(emu_typ, target_typ)) { - printf("Error: TODO: %s: emulated and target types are different\n", string_content(req->obj_name)); + if (emu_typ->typ != target_typ->typ) { + printf("Error: %s: emulated and target types are different (emulated is %u, target is %u)\n", + string_content(req->obj_name), emu_typ->typ, target_typ->typ); return 0; } if (emu_typ->typ == TYPE_FUNCTION) { @@ -978,16 +1666,17 @@ int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(c printf("Error: failed to create function type string\n"); return 0; } - if (!convert_type(req->val.fun.typ, emu_typ->val.fun.ret, 1, &needs_D, &needs_my, conv_map, req->obj_name)) goto fun_fail; + if (!convert_type(req->val.fun.typ, emu_typ->val.fun.ret, target_typ->val.fun.ret, &req->val.fun.needs_S, &needs_D, &needs_my, conv_map, req->obj_name)) + goto fun_fail; idx_conv = string_len(req->val.fun.typ); if (!string_add_char(req->val.fun.typ, 'F')) { printf("Error: failed to add convention char\n"); goto fun_fail; } - convert_post = convert_type_post(req->val.fun.typ, emu_typ->val.fun.ret, req->obj_name); + convert_post = convert_type_post(req->val.fun.typ, emu_typ->val.fun.ret, target_typ->val.fun.ret, req->obj_name); if (!convert_post) goto fun_fail; if (emu_typ->val.fun.nargs == (size_t)-1) { - printf("Warning: assuming empty specification is void specification\n"); + printf("Warning: %s: assuming empty specification is void specification\n", string_content(req->obj_name)); if (convert_post == 1) { if (!string_add_char(req->val.fun.typ, 'v')) { printf("Error: failed to add void specification char\n"); @@ -1003,7 +1692,8 @@ int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(c } } else { for (size_t i = 0; i < emu_typ->val.fun.nargs; ++i) { - if (!convert_type(req->val.fun.typ, emu_typ->val.fun.args[i], 0, &needs_D, &needs_my, conv_map, req->obj_name)) goto fun_fail; + if (!convert_type(req->val.fun.typ, emu_typ->val.fun.args[i], target_typ->val.fun.args[i], NULL, &needs_D, &needs_my, conv_map, req->obj_name)) + goto fun_fail; } if (emu_typ->val.fun.has_varargs) { if (req->def.fun.typ @@ -1070,15 +1760,20 @@ int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(c return 0; } else { int needs_D = 0, needs_my = req->def.dat.has_size && (req->def.rty == RQT_DATAM); - if (is_simple_type(emu_typ, &needs_D, &needs_my, conv_map)) { - // TODO: Hmm... + switch (get_safeness(emu_typ, target_typ, &needs_D, &needs_my, conv_map, req->obj_name)) { + case SAFE_EXPAND: + needs_my = 1; + /* FALLTHROUGH */ + case SAFE_OK: req->val.rty = needs_my ? RQT_DATAM : req->def.rty; req->val.dat.has_size = 1; req->val.dat.sz = emu_typ->szinfo.size; req->has_val = 1; return 1; - } else { - printf("Error: TODO: solve_request for data %s with non-simple type ", string_content(req->obj_name)); + + case SAFE_ABORT: + default: + log_TODO_nopos("solve_request for data %s with non-simple type ", string_content(req->obj_name)); type_print(emu_typ); printf("\n"); return 0; @@ -1095,6 +1790,7 @@ int solve_request_map(request_t *req, khash_t(decl_map) *emu_decl_map, khash_t(d if ((kh_val(emu_decl_map, emuit)->storage == STORAGE_STATIC) || (kh_val(emu_decl_map, emuit)->storage == STORAGE_TLS_STATIC)) { goto failed; } + hasemu = 1; targetit = kh_get(decl_map, target_decl_map, string_content(req->obj_name)); if (targetit == kh_end(target_decl_map)) { goto failed; @@ -1102,6 +1798,7 @@ int solve_request_map(request_t *req, khash_t(decl_map) *emu_decl_map, khash_t(d if ((kh_val(target_decl_map, targetit)->storage == STORAGE_STATIC) || (kh_val(target_decl_map, targetit)->storage == STORAGE_TLS_STATIC)) { goto failed; } + hastarget = 1; return solve_request(req, kh_val(emu_decl_map, emuit)->typ, kh_val(target_decl_map, targetit)->typ, conv_map); failed: diff --git a/wrapperhelper/src/generator.h b/wrapperhelper/src/generator.h index 4d8ef1204..89044af78 100644 --- a/wrapperhelper/src/generator.h +++ b/wrapperhelper/src/generator.h @@ -28,6 +28,7 @@ typedef struct request_s { struct { string_t *typ; string_t *fun2; + _Bool needs_S; } fun; struct { int has_size; @@ -57,6 +58,13 @@ void references_print_check(const VECTOR(references) *refs); void output_from_references(FILE *f, const VECTOR(references) *reqs); VECTOR(references) *references_from_file(const char *filename, FILE *f); // Takes ownership of f + +// Simple solvers (emu and target have the same pointer size) +int solve_request_simple(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(conv_map) *conv_map); +int solve_request_map_simple(request_t *req, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map); +int solve_references_simple(VECTOR(references) *reqs, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map); + +// Complex solvers (emu and target have different pointer size) int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(conv_map) *conv_map); int solve_request_map(request_t *req, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map); int solve_references(VECTOR(references) *reqs, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map); diff --git a/wrapperhelper/src/lang.c b/wrapperhelper/src/lang.c index c3b5ca198..85c2096e2 100644 --- a/wrapperhelper/src/lang.c +++ b/wrapperhelper/src/lang.c @@ -156,44 +156,46 @@ const char *sym2str[LAST_SYM + 1] = { }; void preproc_token_print(const preproc_token_t *tok) { + printf("Token: "); + loginfo_print(&tok->loginfo, 50); switch (tok->tokt) { case PPTOK_INVALID: - printf("Token: %7s %hhd (%c)\n", "#INVAL#", tok->tokv.c, (tok->tokv.c >= 0x20) && (tok->tokv.c < 0x7F) ? tok->tokv.c : '?'); + printf("%7s %hhd (%c)\n", "#INVAL#", tok->tokv.c, (tok->tokv.c >= 0x20) && (tok->tokv.c < 0x7F) ? tok->tokv.c : '?'); break; case PPTOK_IDENT: - printf("Token: %7s '%s'\n", "IDENT", string_content(tok->tokv.str)); + printf("%7s '%s'\n", "IDENT", string_content(tok->tokv.str)); break; case PPTOK_IDENT_UNEXP: - printf("Token: %7s '%s'\n", "IDENT'", string_content(tok->tokv.str)); + printf("%7s '%s'\n", "IDENT'", string_content(tok->tokv.str)); break; case PPTOK_NUM: - printf("Token: %7s '%s'\n", "NUM", string_content(tok->tokv.str)); + printf("%7s '%s'\n", "NUM", string_content(tok->tokv.str)); break; case PPTOK_STRING: - printf("Token: %7s %c%s%c\n", "STRING", + printf("%7s %c%s%c\n", "STRING", tok->tokv.sisstr ? '"' : '\'', string_content(tok->tokv.sstr), tok->tokv.sisstr ? '"' : '\''); break; case PPTOK_INCL: - printf("Token: %7s %c%s%c\n", "INCL", + printf("%7s %c%s%c\n", "INCL", tok->tokv.sisstr ? '"' : '<', string_content(tok->tokv.sstr), tok->tokv.sisstr ? '"' : '>'); break; case PPTOK_SYM: - printf("Token: %7s %-3s (%u)\n", "SYM", sym2str[tok->tokv.sym], tok->tokv.sym); + printf("%7s %-3s (%u)\n", "SYM", sym2str[tok->tokv.sym], tok->tokv.sym); break; case PPTOK_NEWLINE: - printf("Token: %7s\n", "NEWLINE"); + printf("%7s\n", "NEWLINE"); break; case PPTOK_BLANK: - printf("Token: %7s\n", "\e[2;31m(blank)\e[m"); + printf("%7s\n", "\e[2;31m(blank)\e[m"); break; case PPTOK_START_LINE_COMMENT: - printf("Token: %7s\n", "\e[2;31m( // ) \e[m"); + printf("%7s\n", "\e[2;31m( // ) \e[m"); break; case PPTOK_EOF: - printf("Token: %7s\n", "EOF"); + printf("%7s\n", "EOF"); break; default: - printf("Token: ??? %u\n", tok->tokt); + printf("??? %u\n", tok->tokt); } } @@ -266,49 +268,51 @@ const char *kw2str[LAST_KEYWORD + 1] = { }; void proc_token_print(const proc_token_t *tok) { + printf("Token: "); + loginfo_print(&tok->loginfo, 50); switch (tok->tokt) { case PTOK_INVALID: - printf("Token: %7s %hhd (%c)\n", "#INVAL#", tok->tokv.c, (tok->tokv.c >= 0x20) && (tok->tokv.c < 0x7F) ? tok->tokv.c : '?'); + printf("%7s %hhd (%c)\n", "#INVAL#", tok->tokv.c, (tok->tokv.c >= 0x20) && (tok->tokv.c < 0x7F) ? tok->tokv.c : '?'); break; case PTOK_IDENT: - printf("Token: %7s '%s'\n", "IDENT", string_content(tok->tokv.str)); + printf("%7s '%s'\n", "IDENT", string_content(tok->tokv.str)); break; case PTOK_KEYWORD: - printf("Token: %7s '%s' (%u)\n", "KEYWORD", kw2str[tok->tokv.kw], tok->tokv.kw); + printf("%7s '%s' (%u)\n", "KEYWORD", kw2str[tok->tokv.kw], tok->tokv.kw); break; case PTOK_NUM: - printf("Token: %7s '%s'\n", "NUM", string_content(tok->tokv.str)); + printf("%7s '%s'\n", "NUM", string_content(tok->tokv.str)); break; case PTOK_STRING: - printf("Token: %7s %c%s%c\n", "STRING", + printf("%7s %c%s%c\n", "STRING", tok->tokv.sisstr ? '"' : '\'', string_content(tok->tokv.sstr), tok->tokv.sisstr ? '"' : '\''); break; case PTOK_SYM: - printf("Token: %7s %-3s (%u)\n", "SYM", sym2str[tok->tokv.sym], tok->tokv.sym); + printf("%7s %-3s (%u)\n", "SYM", sym2str[tok->tokv.sym], tok->tokv.sym); break; case PTOK_PRAGMA: switch (tok->tokv.pragma.typ) { case PRAGMA_ALLOW_INTS: - printf("Token: %7s Allow ints\n", "PRAGMA"); + printf("%7s Allow ints\n", "PRAGMA"); break; case PRAGMA_SIMPLE_SU: - printf("Token: %7s Mark simple: struct or union %s is simple\n", "PRAGMA", string_content(tok->tokv.pragma.val)); + printf("%7s Mark simple: struct or union %s is simple\n", "PRAGMA", string_content(tok->tokv.pragma.val)); break; case PRAGMA_EXPLICIT_CONV: - printf("Token: %7s Relaxed explicit conversion: destination is %s\n", "PRAGMA", string_content(tok->tokv.pragma.val)); + printf("%7s Relaxed explicit conversion: destination is %s\n", "PRAGMA", string_content(tok->tokv.pragma.val)); break; case PRAGMA_EXPLICIT_CONV_STRICT: - printf("Token: %7s Strict explicit conversion: destination is %s\n", "PRAGMA", string_content(tok->tokv.pragma.val)); + printf("%7s Strict explicit conversion: destination is %s\n", "PRAGMA", string_content(tok->tokv.pragma.val)); break; default: - printf("Token: %7s ???\n", "PRAGMA"); + printf("%7s ??? %u\n", "PRAGMA", tok->tokv.pragma.typ); } break; case PTOK_EOF: - printf("Token: %7s\n", "EOF"); + printf("%7s\n", "EOF"); break; default: - printf("Token: ??? %u\n", tok->tokt); + printf("??? %u\n", tok->tokt); } } @@ -356,26 +360,26 @@ khash_t(str2kw) *str2kw; int init_str2kw(void) { if (!(str2kw = kh_init(str2kw))) { - printf("Failed to create the string to keyword map (init)\n"); + log_memory("failed to create the string to keyword map (init)\n"); return 0; } int iret; khiter_t it; for (enum token_keyword_type_e kw = 0; kw <= LAST_KEYWORD; ++kw) { it = kh_put(str2kw, str2kw, kw2str[kw], &iret); if (iret < 0) { - printf("Failed to create the string to keyword map (keyword %u)\n", kw); + log_memory("failed to create the string to keyword map (keyword %u)\n", kw); kh_destroy(str2kw, str2kw); return 0; } kh_val(str2kw, it) = kw; } #define ADD_ALIAS(alias, k) \ - it = kh_put(str2kw, str2kw, #alias, &iret); \ - if (iret < 0) { \ - printf("Failed to create the string to keyword map (keyword alias " #alias ")\n"); \ - kh_destroy(str2kw, str2kw); \ - return 0; \ - } \ + it = kh_put(str2kw, str2kw, #alias, &iret); \ + if (iret < 0) { \ + log_memory("failed to create the string to keyword map (keyword alias " #alias ")\n"); \ + kh_destroy(str2kw, str2kw); \ + return 0; \ + } \ kh_val(str2kw, it) = KW_ ## k; ADD_ALIAS(__alignof__, ALIGNOF) // ADD_ALIAS(__asm, asm) @@ -404,8 +408,8 @@ void del_str2kw(void) { kh_destroy(str2kw, str2kw); } -// ptr_is_32bits is actially long_is_32bits -int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits) { +// ptr_is_32bits is actually long_is_32bits +int num_constant_convert(loginfo_t *li, string_t *str, num_constant_t *cst, int ptr_is_32bits) { if (string_len(str) == 0) return 0; // Should never happen #define contains(c) strchr(string_content(str), c) if (contains('.') @@ -430,10 +434,10 @@ int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits) ok = (endc == string_end(str)); } if (!ok) { - printf("Error: '%s' is not a valid number\n", string_content(str)); + log_error(li, "'%s' is not a valid number\n", string_content(str)); return 0; } else if (errno == ERANGE) { - printf("Warning: floating point constant is too large\n"); + log_warning(li, "floating point constant is too large\n"); return 1; } return 1; @@ -451,14 +455,14 @@ int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits) remove_suffix: if ((string_content(str)[endidx - 1] == 'l') || (string_content(str)[endidx - 1] == 'L')) { if (suffix_type & SUFFIX_SZ) { - printf("Error: '%s' is not a valid number (invalid suffix)\n", string_content(str)); + log_error(li, "'%s' is not a valid number (invalid suffix)\n", string_content(str)); return 0; } if (endidx == 1) return 0; // Should never happen if ((string_content(str)[endidx - 2] == 'l') || (string_content(str)[endidx - 2] == 'L')) { if (endidx == 2) return 0; // Should never happen if (string_content(str)[endidx - 2] != string_content(str)[endidx - 1]) { - printf("Error: '%s' is not a valid number (invalid suffix)\n", string_content(str)); + log_error(li, "'%s' is not a valid number (invalid suffix)\n", string_content(str)); return 0; } endidx -= 2; @@ -471,7 +475,7 @@ int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits) } if ((string_content(str)[endidx - 1] == 'u') || (string_content(str)[endidx - 1] == 'U')) { if (suffix_type & SUFFIX_SGN) { - printf("Error: '%s' is not a valid number (invalid suffix)\n", string_content(str)); + log_error(li, "'%s' is not a valid number (invalid suffix)\n", string_content(str)); return 0; } endidx -= 1; @@ -480,7 +484,7 @@ int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits) } // 0u has startidx=0 endidx=1 if (endidx <= startidx) { - printf("Error: '%s' is not a valid number\n", string_content(str)); + log_error(li, "'%s' is not a valid number\n", string_content(str)); } for (size_t i = startidx; i < endidx; ++i) { if ((string_content(str)[i] >= '0') && (string_content(str)[i] <= ((base == 8) ? '7' : '9'))) { @@ -490,7 +494,7 @@ int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits) } else if ((base == 16) && (string_content(str)[i] >= 'a') && (string_content(str)[i] <= 'f')) { ret = base * ret + 10 + (unsigned)(string_content(str)[i] - 'a'); } else { - printf("Error: '%s' is not a valid number\n", string_content(str)); + log_error(li, "'%s' is not a valid number\n", string_content(str)); return 0; } } @@ -590,6 +594,151 @@ void expr_del(expr_t *e) { free(e); } +static void expr_print_aux(expr_t *e, int parent_level) { + switch (e->typ) { + case ETY_VAR: + // Level 0, no parenthesis + printf("%s", string_content(e->val.var)); + break; + + case ETY_CONST: + // Level 0, no parenthesis + switch (e->val.cst.typ) { + case NCT_FLOAT: printf("%ff", e->val.cst.val.f); break; + case NCT_DOUBLE: printf("%f", e->val.cst.val.d); break; + case NCT_LDOUBLE: printf("%Lfl", e->val.cst.val.l); break; + case NCT_INT32: printf("%d", e->val.cst.val.i32); break; + case NCT_UINT32: printf("%uu", e->val.cst.val.u32); break; + case NCT_INT64: printf("%ldll", e->val.cst.val.i64); break; + case NCT_UINT64: printf("%lullu", e->val.cst.val.u64); break; + } + break; + + case ETY_CALL: + // Level 1, no parenthesis + expr_print_aux(e->val.call.fun, 1); + printf("("); + for (size_t i = 0; i < e->val.call.nargs; ++i) { + expr_print_aux(e->val.call.fun, 15); + } + printf(")"); + break; + + case ETY_ACCESS: + // Level 1, no parenthesis + expr_print_aux(e->val.access.val, 1); + printf(".%s", string_content(e->val.access.member)); + break; + + case ETY_PTRACCESS: + // Level 1, no parenthesis + expr_print_aux(e->val.access.val, 1); + printf(".%s", string_content(e->val.access.member)); + break; + + case ETY_UNARY: { + const char *preop = NULL; + switch (e->val.unary.typ) { + case UOT_POSTINCR: + // Level 1, no parenthesis + expr_print_aux(e->val.unary.e, 1); + printf("++"); + break; + case UOT_POSTDECR: + // Level 1, no parenthesis + expr_print_aux(e->val.unary.e, 1); + printf("--"); + break; + case UOT_PREINCR: preop = "++"; break; + case UOT_PREDECR: preop = "--"; break; + case UOT_REF: preop = "&"; break; + case UOT_POS: preop = "+"; break; + case UOT_NEG: preop = "-"; break; + case UOT_DEREF: preop = "*"; break; + case UOT_ANOT: preop = "~"; break; + case UOT_BNOT: preop = "!"; break; + } + if (preop) { + if (parent_level < 2) printf("("); + printf("%s", preop); + expr_print_aux(e->val.unary.e, 2); + if (parent_level < 2) printf(")"); + } + break; } + + case ETY_BINARY: { + const char *midop, *postop = NULL; + int mlevel, llevel, rlevel; + switch (e->val.binary.typ) { + case BOT_ADD: mlevel = 5; llevel = 5; rlevel = 4; midop = " + "; break; + case BOT_SUB: mlevel = 5; llevel = 5; rlevel = 4; midop = " - "; break; + case BOT_MUL: mlevel = 4; llevel = 4; rlevel = 3; midop = " * "; break; + case BOT_DIV: mlevel = 4; llevel = 4; rlevel = 3; midop = " / "; break; + case BOT_MOD: mlevel = 4; llevel = 4; rlevel = 3; midop = " % "; break; + case BOT_LSH: mlevel = 6; llevel = 6; rlevel = 5; midop = " << "; break; + case BOT_RSH: mlevel = 6; llevel = 6; rlevel = 5; midop = " >> "; break; + case BOT_LT: mlevel = 7; llevel = 7; rlevel = 6; midop = " < "; break; + case BOT_GT: mlevel = 7; llevel = 7; rlevel = 6; midop = " > "; break; + case BOT_LE: mlevel = 7; llevel = 7; rlevel = 6; midop = " <= "; break; + case BOT_GE: mlevel = 7; llevel = 7; rlevel = 6; midop = " >= "; break; + case BOT_EQ: mlevel = 8; llevel = 8; rlevel = 7; midop = " == "; break; + case BOT_NE: mlevel = 8; llevel = 8; rlevel = 7; midop = " != "; break; + case BOT_AAND: mlevel = 9; llevel = 9; rlevel = 8; midop = " & "; break; + case BOT_AXOR: mlevel = 10; llevel = 10; rlevel = 9; midop = " ^ "; break; + case BOT_AOR: mlevel = 11; llevel = 11; rlevel = 10; midop = " | "; break; + case BOT_BAND: mlevel = 12; llevel = 12; rlevel = 11; midop = " && "; break; + case BOT_BOR: mlevel = 13; llevel = 13; rlevel = 12; midop = " || "; break; + case BOT_ASSGN_EQ: mlevel = 15; llevel = 2; rlevel = 15; midop = " = "; break; + case BOT_ASSGN_ADD: mlevel = 15; llevel = 2; rlevel = 15; midop = " += "; break; + case BOT_ASSGN_SUB: mlevel = 15; llevel = 2; rlevel = 15; midop = " -= "; break; + case BOT_ASSGN_MUL: mlevel = 15; llevel = 2; rlevel = 15; midop = " *= "; break; + case BOT_ASSGN_DIV: mlevel = 15; llevel = 2; rlevel = 15; midop = " /= "; break; + case BOT_ASSGN_MOD: mlevel = 15; llevel = 2; rlevel = 15; midop = " %= "; break; + case BOT_ASSGN_LSH: mlevel = 15; llevel = 2; rlevel = 15; midop = " <<= "; break; + case BOT_ASSGN_RSH: mlevel = 15; llevel = 2; rlevel = 15; midop = " >>= "; break; + case BOT_ASSGN_AAND: mlevel = 15; llevel = 2; rlevel = 15; midop = " &= "; break; + case BOT_ASSGN_AXOR: mlevel = 15; llevel = 2; rlevel = 15; midop = " ^= "; break; + case BOT_ASSGN_AOR: mlevel = 15; llevel = 2; rlevel = 15; midop = " |= "; break; + case BOT_COMMA: mlevel = 16; llevel = 16; rlevel = 15; midop = ", "; break; + case BOT_ARRAY: mlevel = 1; llevel = 1; rlevel = 16; midop = "["; postop = "]"; break; + default: mlevel = 17; llevel = rlevel = -1; midop = " ? "; break; + } + if (parent_level < mlevel) printf("("); + expr_print_aux(e->val.binary.e1, llevel); + printf("%s", midop); + expr_print_aux(e->val.binary.e2, rlevel); + if (postop) printf("%s", midop); + if (parent_level < mlevel) printf(")"); + break; } + + case ETY_TERNARY: + switch (e->val.ternary.typ) { + case TOT_COND: + if (parent_level < 15) printf("("); + expr_print_aux(e->val.ternary.e1, 14); + printf(" ? "); + expr_print_aux(e->val.ternary.e2, 16); + expr_print_aux(e->val.ternary.e2, 15); + printf(" : "); + if (parent_level < 15) printf(")"); + break; + } + break; + + case ETY_CAST: + if (parent_level < 3) printf("("); + printf("("); + type_print(e->val.cast.typ); + printf(")"); + expr_print(e->val.cast.e); + if (parent_level < 3) printf(")"); + break; + } +} +void expr_print(expr_t *e) { + return expr_print_aux(e, 16); +} + void struct_del_weak(struct_t *st) { if (--st->nrefs) return; if (!st->tag) struct_del(st); @@ -701,7 +850,7 @@ void struct_map_del(khash_t(struct_map) *map) { type_t *type_new(void) { type_t *ret = malloc(sizeof *ret); if (!ret) { - printf("Failed to create a new type\n"); + log_memory("failed to create a new type\n"); return NULL; } ret->szinfo.align = ret->szinfo.size = 0; @@ -715,7 +864,7 @@ type_t *type_new(void) { type_t *type_new_ptr(type_t *target) { type_t *ret = malloc(sizeof *ret); if (!ret) { - printf("Failed to create a new pointer type\n"); + log_memory("failed to create a new pointer type\n"); return NULL; } ret->szinfo.align = ret->szinfo.size = 0; @@ -755,7 +904,7 @@ int type_copy_into(type_t *dest, const type_t *ref) { } type_t **args = malloc(sizeof *args * ref->val.fun.nargs); if (!args) { - printf("Error: failed to allocate new argument array\n"); + log_memory("failed to allocate new argument array\n"); return 0; } for (size_t i = 0; i < ref->val.fun.nargs; ++i) { @@ -777,7 +926,7 @@ int type_copy_into(type_t *dest, const type_t *ref) { struct_t *struct_new(int is_struct, string_t *tag) { struct_t *ret = malloc(sizeof *ret); if (!ret) { - printf("Failed to create a new struct\n"); + log_memory("Error: failed to create a new struct\n"); return NULL; } ret->is_struct = is_struct; @@ -785,6 +934,7 @@ struct_t *struct_new(int is_struct, string_t *tag) { ret->is_defined = 0; ret->is_simple = 0; ret->nrefs = 1; + ret->has_self_recursion = 0; // Undefined structures cannot have self recursion return ret; } @@ -831,7 +981,7 @@ int type_t_equal_aux(type_t *typ1, type_t *typ2, int is_strict) { if (!typ1->val.st->tag != !typ2->val.st->tag) return 0; if (typ1->val.st->tag) return !strcmp(string_content(typ1->val.st->tag), string_content(typ2->val.st->tag)); if (!typ1->val.st->is_defined || !typ2->val.st->is_defined) { - printf("Warning: incomplete anonymous structure/union\n"); + log_warning_nopos("comparing against incomplete anonymous structure/union\n"); return 0; } if (typ1->val.st->nmembers != typ2->val.st->nmembers) return 0; @@ -872,7 +1022,7 @@ type_t *type_try_merge(type_t *typ, khash_t(type_set) *set) { int iret; khiter_t it = kh_put(type_set, set, typ, &iret); if (iret < 0) { - printf("Error: failed to add type to type_set\n"); + log_memory("Error: failed to add type to type_set\n"); return NULL; } else if (iret == 0) { if (typ == kh_key(set, it)) return typ; @@ -1030,11 +1180,12 @@ void struct_print(const struct_t *st) { } if (st->is_defined) { printf( - "%s %s { ", + "%s %s { ", st->is_struct ? "struct" : "union", st->tag ? string_content(st->tag) : "", st->nmembers, - st->has_incomplete ? ", with incomplete" : ""); + st->has_incomplete ? ", with incomplete" : "", + st->has_self_recursion ? ", with self-recursion" : ""); for (size_t i = 0; i < st->nmembers; ++i) { if (i) printf(", "); type_print(st->members[i].typ); @@ -1052,29 +1203,29 @@ void struct_print(const struct_t *st) { file_t *file_new(machine_t *target) { file_t *ret = malloc(sizeof *ret); if (!ret) { - printf("Failed to create a new translation unit structure (init)\n"); + log_memory("failed to create a new translation unit structure (init)\n"); return NULL; } if (!(ret->struct_map = kh_init(struct_map))) { - printf("Failed to create a new translation unit structure (structure map)\n"); + log_memory("failed to create a new translation unit structure (structure map)\n"); free(ret); return NULL; } if (!(ret->type_map = kh_init(type_map))) { - printf("Failed to create a new translation unit structure (type map)\n"); + log_memory("failed to create a new translation unit structure (type map)\n"); kh_destroy(struct_map, ret->struct_map); free(ret); return NULL; } if (!(ret->enum_map = kh_init(type_map))) { - printf("Failed to create a new translation unit structure (enumeration map)\n"); + log_memory("failed to create a new translation unit structure (enumeration map)\n"); kh_destroy(struct_map, ret->struct_map); kh_destroy(type_map, ret->type_map); free(ret); return NULL; } if (!(ret->decl_map = kh_init(decl_map))) { - printf("Failed to create a new translation unit structure (declaration map)\n"); + log_memory("failed to create a new translation unit structure (declaration map)\n"); kh_destroy(struct_map, ret->struct_map); kh_destroy(type_map, ret->type_map); kh_destroy(type_map, ret->enum_map); @@ -1082,7 +1233,7 @@ file_t *file_new(machine_t *target) { return NULL; } if (!(ret->type_set = kh_init(type_set))) { - printf("Failed to create a new translation unit structure (type set)\n"); + log_memory("failed to create a new translation unit structure (type set)\n"); kh_destroy(struct_map, ret->struct_map); kh_destroy(type_map, ret->type_map); kh_destroy(type_map, ret->enum_map); @@ -1091,7 +1242,7 @@ file_t *file_new(machine_t *target) { return NULL; } if (!(ret->const_map = kh_init(const_map))) { - printf("Failed to create a new translation unit structure (const map)\n"); + log_memory("failed to create a new translation unit structure (const map)\n"); kh_destroy(struct_map, ret->struct_map); kh_destroy(type_map, ret->type_map); kh_destroy(type_map, ret->enum_map); @@ -1101,7 +1252,7 @@ file_t *file_new(machine_t *target) { return NULL; } if (!(ret->relaxed_type_conversion = kh_init(conv_map))) { - printf("Failed to create a new translation unit structure (relaxed type conversion map)\n"); + log_memory("failed to create a new translation unit structure (relaxed type conversion map)\n"); kh_destroy(struct_map, ret->struct_map); kh_destroy(type_map, ret->type_map); kh_destroy(type_map, ret->enum_map); @@ -1117,7 +1268,7 @@ file_t *file_new(machine_t *target) { for (enum type_builtin_e i = 0; i < LAST_BUILTIN + 1; ++i) { type_t *t = type_new(); if (!t) { - printf("Failed to create a new translation unit structure (builtin type)\n"); + log_memory("failed to create a new translation unit structure (builtin type)\n"); for (; i--;) { free(ret->builtins[i]); } @@ -1135,11 +1286,14 @@ file_t *file_new(machine_t *target) { t->nrefs = 2; t->typ = TYPE_BUILTIN; t->val.builtin = i; - validate_type(target, t); + if (!target->has_int128 && ((i == BTT_INT128) || (i == BTT_SINT128) || (i == BTT_UINT128))) { + t->converted = string_new_cstr(""); + } + validate_type(&(loginfo_t){0}, target, t); ret->builtins[i] = t; kh_put(type_set, ret->type_set, t, &iret); if (iret < 0) { - printf("Failed to create a new translation unit structure (failed to add intrinsic type to type_set)\n"); + log_memory("failed to create a new translation unit structure (failed to add intrinsic type to type_set)\n"); kh_destroy(struct_map, ret->struct_map); kh_destroy(type_map, ret->type_map); kh_destroy(conv_map, ret->relaxed_type_conversion); @@ -1150,7 +1304,7 @@ file_t *file_new(machine_t *target) { free(ret); return NULL; } else if (iret == 0) { - printf("Failed to create a new translation unit structure (duplicate intrinsic type in type_set)\n"); + log_memory("failed to create a new translation unit structure (duplicate intrinsic type in type_set)\n"); for (++i; i--;) { free(ret->builtins[i]); } @@ -1167,32 +1321,34 @@ file_t *file_new(machine_t *target) { } // ret is valid and can now be deleted by file_del - // Add __builtin_va_list, __int128_t, __uint128_t as typedef + // Add __builtin_va_list, __int128_t, __uint128_t as builtin typedef char *sdup; #define ADD_TYPEDEF(name, btt) \ - sdup = strdup(#name); \ - if (!sdup) { \ - printf("Failed to create a new translation unit structure (" #name " name)\n"); \ - file_del(ret); \ - return NULL; \ - } \ - it = kh_put(type_map, ret->type_map, sdup, &iret); \ - if (iret < 0) { \ - printf("Failed to create a new translation unit structure (add " #name " typedef)\n"); \ - free(sdup); \ - file_del(ret); \ - return NULL; \ - } else if (iret == 0) { \ - printf("Failed to create a new translation unit structure (" #name " is already a typedef)\n"); \ - free(sdup); \ - file_del(ret); \ - return NULL; \ - } \ - kh_val(ret->type_map, it) = ret->builtins[BTT_ ## btt]; \ + sdup = strdup(#name); \ + if (!sdup) { \ + log_memory("failed to create a new translation unit structure (" #name " name)\n"); \ + file_del(ret); \ + return NULL; \ + } \ + it = kh_put(type_map, ret->type_map, sdup, &iret); \ + if (iret < 0) { \ + log_memory("failed to create a new translation unit structure (add " #name " typedef)\n"); \ + free(sdup); \ + file_del(ret); \ + return NULL; \ + } else if (iret == 0) { \ + log_memory("failed to create a new translation unit structure (" #name " is already a typedef)\n"); \ + free(sdup); \ + file_del(ret); \ + return NULL; \ + } \ + kh_val(ret->type_map, it) = ret->builtins[BTT_ ## btt]; \ ++ret->builtins[BTT_ ## btt]->nrefs; ADD_TYPEDEF(__builtin_va_list, VA_LIST) - ADD_TYPEDEF(__int128_t, INT128) - ADD_TYPEDEF(__uint128_t, UINT128) + if (target->has_int128) { + ADD_TYPEDEF(__int128_t, INT128) + ADD_TYPEDEF(__uint128_t, UINT128) + } return ret; } diff --git a/wrapperhelper/src/lang.h b/wrapperhelper/src/lang.h index e10b85426..e921013ce 100644 --- a/wrapperhelper/src/lang.h +++ b/wrapperhelper/src/lang.h @@ -5,6 +5,7 @@ #include "cstring.h" #include "khash.h" +#include "log.h" #include "machine.h" #include "vector.h" @@ -75,6 +76,7 @@ typedef struct preproc_token_s { PPTOK_START_LINE_COMMENT, PPTOK_EOF } tokt; + loginfo_t loginfo; union { string_t *str; struct { @@ -150,6 +152,7 @@ typedef struct proc_token_s { PTOK_PRAGMA, PTOK_EOF } tokt; + loginfo_t loginfo; union proc_token_val_u { string_t *str; struct { @@ -193,7 +196,7 @@ typedef struct num_constant_s { uint64_t u64; } val; } num_constant_t; -int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits); +int num_constant_convert(loginfo_t *li, string_t *str, num_constant_t *cst, int ptr_is_32bits); KHASH_MAP_DECLARE_STR(const_map, num_constant_t) typedef struct expr_s { @@ -288,6 +291,7 @@ typedef struct expr_s { } val; } expr_t; void expr_del(expr_t *e); +void expr_print(expr_t *e); typedef struct size_info_s { size_t size, align; @@ -387,7 +391,8 @@ typedef struct st_member_s { type_t *typ; _Bool is_bitfield; size_t bitfield_width; - // TODO: add byte_offset then check in generator against both archs for every named members + // Filled by validate_type + size_t byte_offset; unsigned char bit_offset; } st_member_t; typedef struct struct_s { string_t *tag; @@ -396,6 +401,7 @@ typedef struct struct_s { int is_struct; // 0 = union, 1 = struct int is_simple; // Pointers to the structure (in 64 bits) are simple pointers int has_incomplete; // 1 if the last element of the structure is a VLA or if an element of the union recursively contains a VLA + int has_self_recursion; // 1 if the structure contains a reference to itself size_t nmembers; st_member_t *members; } struct_t; diff --git a/wrapperhelper/src/log.c b/wrapperhelper/src/log.c new file mode 100644 index 000000000..a50b52a12 --- /dev/null +++ b/wrapperhelper/src/log.c @@ -0,0 +1,80 @@ +#include "log.h" + +#include +#include + +void loginfo_print(const loginfo_t *info, int print_sz) { + if (!info) { + if (print_sz > 0) printf("%*s", print_sz, ""); + return; + } + if (!info->filename) { + if (print_sz > 0) printf("%*s", print_sz, ""); + return; + } + print_sz -= printf("%s:", info->filename); + if (!info->lineno) { + print_sz -= printf(" "); + if (print_sz > 0) printf("%*s", print_sz, ""); + return; + } + print_sz -= printf("%zu:", info->lineno); + if (!info->colno) { + print_sz -= printf(" "); + if (print_sz > 0) printf("%*s", print_sz, ""); + return; + } + print_sz -= printf("%zu", info->colno); + if (!info->lineno_end || ((info->lineno_end == info->lineno) && (info->colno_end == info->colno))) { + print_sz -= printf(": "); + if (print_sz > 0) printf("%*s", print_sz, ""); + return; + } + print_sz -= printf("-"); + if (info->lineno_end != info->lineno) { + print_sz -= printf("%zu:", info->lineno_end); + } + print_sz -= printf("%zu: ", info->colno_end + 1); + if (print_sz > 0) printf("%*s", print_sz, ""); +} + +void log_error(const loginfo_t *info, const char *format, ...) { + printf("Error: "); + loginfo_print(info, 0); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} +void log_internal(const loginfo_t *info, const char *format, ...) { + printf("Internal error: "); + loginfo_print(info, 0); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} +void log_memory(const char *format, ...) { + printf("Fatal error: memory error: "); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} +void log_TODO(const loginfo_t *info, const char *format, ...) { + printf("Error: "); + loginfo_print(info, 0); + printf("TODO: "); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} +void log_warning(const loginfo_t *info, const char *format, ...) { + printf("Warning: "); + loginfo_print(info, 0); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} diff --git a/wrapperhelper/src/log.h b/wrapperhelper/src/log.h new file mode 100644 index 000000000..e1f210b68 --- /dev/null +++ b/wrapperhelper/src/log.h @@ -0,0 +1,27 @@ +#ifndef __LOG_H__ +#define __LOG_H__ + +#include + +typedef struct loginfo_s { + const char *filename; // NULL = no log info + size_t lineno; // 0 = no (start) line/column number + size_t colno; + size_t lineno_end; // 0 = no end line/column number + size_t colno_end; +} loginfo_t; + +#define ATTRIBUTE_FORMAT(i, j) __attribute__((format(printf, i, j))) + +void loginfo_print(const loginfo_t *info, int print_sz); // print_sz = min characters output +void log_error(const loginfo_t *info, const char *format, ...) ATTRIBUTE_FORMAT(2, 3); +void log_internal(const loginfo_t *info, const char *format, ...) ATTRIBUTE_FORMAT(2, 3); +void log_memory(const char *format, ...) ATTRIBUTE_FORMAT(1, 2); +void log_TODO(const loginfo_t *info, const char *format, ...) ATTRIBUTE_FORMAT(2, 3); +void log_warning(const loginfo_t *info, const char *format, ...) ATTRIBUTE_FORMAT(2, 3); +#define log_error_nopos(...) log_error(&(loginfo_t){0}, __VA_ARGS__) +#define log_internal_nopos(...) log_internal(&(loginfo_t){0}, __VA_ARGS__) +#define log_TODO_nopos(...) log_TODO(&(loginfo_t){0}, __VA_ARGS__) +#define log_warning_nopos(...) log_warning(&(loginfo_t){0}, __VA_ARGS__) + +#endif // __LOG_H__ diff --git a/wrapperhelper/src/machine.c b/wrapperhelper/src/machine.c index b89a64ae4..499bcb2fa 100644 --- a/wrapperhelper/src/machine.c +++ b/wrapperhelper/src/machine.c @@ -5,7 +5,7 @@ #include "lang.h" machine_t machine_x86_64; -// machine_t machine_x86; +machine_t machine_x86; machine_t machine_aarch64; #define PASTE2(a, b) a ## b @@ -17,23 +17,23 @@ machine_t machine_aarch64; #define PATHS_OFFSET_PRE 2 // There are two paths that are always included before any other #define ADD_PATH(path) \ - if (!(MACHINE_VAL.include_path[failure_id] = strdup(path))) { \ - printf("Failed to add include path to " MACHINE_STR " platform\n"); \ - goto PASTE(failed_, PASTE(CUR_MACHINE, _paths)); \ - } \ + if (!(MACHINE_VAL.include_path[failure_id] = strdup(path))) { \ + log_memory("failed to add include path to " MACHINE_STR " platform\n"); \ + goto PASTE(failed_, PASTE(CUR_MACHINE, _paths)); \ + } \ ++failure_id; #define INIT_PATHS \ - MACHINE_VAL.npaths = PATHS_OFFSET_PRE + npaths + paths_offset_post; \ - if (!(MACHINE_VAL.include_path = \ - malloc(MACHINE_VAL.npaths * sizeof *MACHINE_VAL.include_path))) { \ - printf("Failed to add include path to " MACHINE_STR " platform\n"); \ - goto PASTE(failed_, PASTE(CUR_MACHINE, _nopath)); \ - } \ - failure_id = 0; \ - ADD_PATH("include-override/" MACHINE_STR) \ - ADD_PATH("include-override/common") \ - while (failure_id < PATHS_OFFSET_PRE + npaths) { \ - ADD_PATH(extra_include_path[failure_id - PATHS_OFFSET_PRE]) \ + MACHINE_VAL.npaths = PATHS_OFFSET_PRE + npaths + paths_offset_post; \ + if (!(MACHINE_VAL.include_path = \ + malloc(MACHINE_VAL.npaths * sizeof *MACHINE_VAL.include_path))) { \ + log_memory("failed to add include path to " MACHINE_STR " platform\n"); \ + goto PASTE(failed_, PASTE(CUR_MACHINE, _nopath)); \ + } \ + failure_id = 0; \ + ADD_PATH("include-override/" MACHINE_STR) \ + ADD_PATH("include-override/common") \ + while (failure_id < PATHS_OFFSET_PRE + npaths) { \ + ADD_PATH(extra_include_path[failure_id - PATHS_OFFSET_PRE]) \ } int init_machines(size_t npaths, const char *const *extra_include_path) { @@ -48,24 +48,45 @@ int init_machines(size_t npaths, const char *const *extra_include_path) { #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" #define CUR_MACHINE x86_64 machine_x86_64.size_long = 8; + machine_x86_64.align_longdouble = 16; + machine_x86_64.size_longdouble = 16; machine_x86_64.align_valist = 8; machine_x86_64.size_valist = 24; - machine_x86_64.unsigned_char = 1; + machine_x86_64.max_align = 8; + machine_x86_64.has_int128 = 1; + machine_x86_64.unsigned_char = 0; machine_x86_64.unnamed_bitfield_aligns = 0; INIT_PATHS #define DO_PATH ADD_PATH #include "machine.gen" #undef DO_PATH #undef CUR_MACHINE -#pragma GCC diagnostic pop -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#define CUR_MACHINE x86 + machine_x86.size_long = 4; + machine_x86.align_longdouble = 4; + machine_x86.size_longdouble = 12; + machine_x86.align_valist = 4; + machine_x86.size_valist = 4; + machine_x86.max_align = 4; + machine_x86.has_int128 = 0; + machine_x86.unsigned_char = 0; + machine_x86.unnamed_bitfield_aligns = 0; + INIT_PATHS +#define DO_PATH ADD_PATH +#include "machine.gen" +#undef DO_PATH +#undef CUR_MACHINE + #define CUR_MACHINE aarch64 machine_aarch64.size_long = 8; + machine_aarch64.align_longdouble = 16; + machine_aarch64.size_longdouble = 16; machine_aarch64.align_valist = 8; machine_aarch64.size_valist = 32; - machine_aarch64.unsigned_char = 0; + machine_aarch64.max_align = 8; + machine_aarch64.has_int128 = 1; + machine_aarch64.unsigned_char = 1; machine_aarch64.unnamed_bitfield_aligns = 1; INIT_PATHS #define DO_PATH ADD_PATH @@ -82,6 +103,13 @@ int init_machines(size_t npaths, const char *const *extra_include_path) { } free(machine_aarch64.include_path); failed_aarch64_nopath: + failure_id = machine_x86.npaths; +failed_x86_paths: + while (failure_id--) { + free(machine_x86.include_path[failure_id]); + } + free(machine_x86.include_path); +failed_x86_nopath: failure_id = machine_x86_64.npaths; failed_x86_64_paths: while (failure_id--) { @@ -100,100 +128,143 @@ static void machine_del(machine_t *m) { } void del_machines(void) { machine_del(&machine_x86_64); + machine_del(&machine_x86); machine_del(&machine_aarch64); } machine_t *convert_machine_name(const char *archname) { if (!strcmp(archname, "x86_64")) return &machine_x86_64; + if (!strcmp(archname, "x86")) + return &machine_x86; if (!strcmp(archname, "aarch64")) return &machine_aarch64; return NULL; } -int validate_type(machine_t *target, type_t *typ) { +void fill_self_recursion(type_t *typ, struct_t *st) { + if (typ->_internal_use) return; // Recursion, but not self recursion + typ->_internal_use = 1; + switch (typ->typ) { + case TYPE_BUILTIN: break; + case TYPE_ARRAY: + fill_self_recursion(typ->val.array.typ, st); + break; + case TYPE_PTR: + fill_self_recursion(typ->val.typ, st); + break; + case TYPE_FUNCTION: + if (typ->val.fun.nargs != (size_t)-1) { + for (size_t i = 0; (i < typ->val.fun.nargs) && !st->has_self_recursion; ++i) { + fill_self_recursion(typ->val.fun.args[i], st); + } + } + if (!st->has_self_recursion) fill_self_recursion(typ->val.fun.ret, st); + break; + case TYPE_STRUCT_UNION: + if (typ->val.st == st) { + st->has_self_recursion = 1; + break; + } + if (!typ->val.st->is_defined) break; + for (size_t i = 0; (i < typ->val.st->nmembers) && !st->has_self_recursion; ++i) { + fill_self_recursion(typ->val.st->members[i].typ, st); + } + break; + case TYPE_ENUM: + fill_self_recursion(typ->val.typ, st); + break; + } + typ->_internal_use = 0; +} + +int validate_type(loginfo_t *loginfo, machine_t *target, type_t *typ) { if (typ->is_validated) return 1; typ->is_validated = 1; if (typ->is_restrict) { if (typ->typ != TYPE_PTR) { - printf("Error: only pointers to object types may be restrict-qualified\n"); + log_error(loginfo, "only pointers to object types may be restrict-qualified\n"); return 0; } if (typ->val.typ->typ == TYPE_FUNCTION) { - printf("Error: only pointers to object types may be restrict-qualified\n"); + log_error(loginfo, "only pointers to object types may be restrict-qualified\n"); return 0; } } if (typ->is_atomic) { if ((typ->typ == TYPE_ARRAY) || (typ->typ == TYPE_FUNCTION)) { - printf("Error: array types and function types may not be atomic-qualified\n"); + log_error(loginfo, "array types and function types may not be atomic-qualified\n"); return 0; } } switch (typ->typ) { case TYPE_BUILTIN: switch (typ->val.builtin) { - case BTT_VOID: typ->szinfo.align = typ->szinfo.size = 0; break; - case BTT_BOOL: typ->szinfo.align = typ->szinfo.size = 1; break; - case BTT_CHAR: typ->szinfo.align = typ->szinfo.size = 1; break; - case BTT_SCHAR: typ->szinfo.align = typ->szinfo.size = 1; break; - case BTT_UCHAR: typ->szinfo.align = typ->szinfo.size = 1; break; - case BTT_SHORT: typ->szinfo.align = typ->szinfo.size = 2; break; - case BTT_SSHORT: typ->szinfo.align = typ->szinfo.size = 2; break; - case BTT_USHORT: typ->szinfo.align = typ->szinfo.size = 2; break; - case BTT_INT: typ->szinfo.align = typ->szinfo.size = 4; break; - case BTT_SINT: typ->szinfo.align = typ->szinfo.size = 4; break; - case BTT_UINT: typ->szinfo.align = typ->szinfo.size = 4; break; - case BTT_LONG: typ->szinfo.align = typ->szinfo.size = target->size_long; break; - case BTT_SLONG: typ->szinfo.align = typ->szinfo.size = target->size_long; break; - case BTT_ULONG: typ->szinfo.align = typ->szinfo.size = target->size_long; break; - case BTT_LONGLONG: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_SLONGLONG: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_ULONGLONG: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_INT128: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_SINT128: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_UINT128: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_S8: typ->szinfo.align = typ->szinfo.size = 1; break; - case BTT_U8: typ->szinfo.align = typ->szinfo.size = 1; break; - case BTT_S16: typ->szinfo.align = typ->szinfo.size = 2; break; - case BTT_U16: typ->szinfo.align = typ->szinfo.size = 2; break; - case BTT_S32: typ->szinfo.align = typ->szinfo.size = 4; break; - case BTT_U32: typ->szinfo.align = typ->szinfo.size = 4; break; - case BTT_S64: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_U64: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_FLOAT: typ->szinfo.align = typ->szinfo.size = 4; break; - case BTT_CFLOAT: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_IFLOAT: typ->szinfo.align = typ->szinfo.size = 4; break; - case BTT_DOUBLE: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_CDOUBLE: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_IDOUBLE: typ->szinfo.align = typ->szinfo.size = 8; break; - case BTT_LONGDOUBLE: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_CLONGDOUBLE: typ->szinfo.align = 16; typ->szinfo.size = 32; break; - case BTT_ILONGDOUBLE: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_FLOAT128: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_CFLOAT128: typ->szinfo.align = 16; typ->szinfo.size = 32; break; - case BTT_IFLOAT128: typ->szinfo.align = typ->szinfo.size = 16; break; - case BTT_VA_LIST: typ->szinfo.align = target->align_valist; typ->szinfo.size = target->size_valist; break; + case BTT_VOID: typ->szinfo.align = typ->szinfo.size = 0; return 1; + case BTT_BOOL: + case BTT_CHAR: + case BTT_SCHAR: + case BTT_UCHAR: + case BTT_S8: + case BTT_U8: typ->szinfo.align = typ->szinfo.size = 1; return 1; + case BTT_SHORT: + case BTT_SSHORT: + case BTT_USHORT: + case BTT_S16: + case BTT_U16: typ->szinfo.align = typ->szinfo.size = 2; return 1; + case BTT_INT: + case BTT_SINT: + case BTT_UINT: + case BTT_S32: + case BTT_U32: typ->szinfo.align = typ->szinfo.size = 4; return 1; + case BTT_LONGLONG: + case BTT_SLONGLONG: + case BTT_ULONGLONG: + case BTT_S64: + case BTT_U64: typ->szinfo.align = target->max_align; typ->szinfo.size = 8; return 1; + case BTT_LONG: + case BTT_SLONG: + case BTT_ULONG: typ->szinfo.align = typ->szinfo.size = target->size_long; return 1; + case BTT_FLOAT: + case BTT_IFLOAT: typ->szinfo.align = typ->szinfo.size = 4; return 1; + case BTT_CFLOAT: + case BTT_DOUBLE: + case BTT_IDOUBLE: typ->szinfo.align = target->max_align; typ->szinfo.size = 8; return 1; + case BTT_CDOUBLE: typ->szinfo.align = target->max_align; typ->szinfo.size = 16; return 1; + case BTT_LONGDOUBLE: + case BTT_ILONGDOUBLE: typ->szinfo.align = target->align_longdouble; typ->szinfo.size = target->size_longdouble; return 1; + case BTT_CLONGDOUBLE: typ->szinfo.align = target->align_longdouble; typ->szinfo.size = 2*target->size_longdouble; return 1; + case BTT_INT128: + case BTT_SINT128: + case BTT_UINT128: + if (!target->has_int128) { + if (loginfo->filename) log_error(loginfo, "target does not have type __int128\n"); + typ->szinfo.align = typ->szinfo.size = 0; return 0; + } + /* FALLTHROUGH */ + case BTT_FLOAT128: + case BTT_IFLOAT128: typ->szinfo.align = typ->szinfo.size = 16; return 1; + case BTT_CFLOAT128: typ->szinfo.align = 16; typ->szinfo.size = 32; return 1; + case BTT_VA_LIST: typ->szinfo.align = target->align_valist; typ->szinfo.size = target->size_valist; return 1; default: - printf("Unknown builtin %u, cannot fill size info\n", typ->val.builtin); + log_error(loginfo, "unknown builtin %u, cannot fill size info\n", typ->val.builtin); return 0; } - return 1; case TYPE_ARRAY: if (typ->val.array.typ->is_incomplete || (typ->val.array.typ->typ == TYPE_FUNCTION)) { - printf("Error: array types must point to complete object types\n"); + log_error(loginfo, "array types must point to complete object types\n"); return 0; } if ((typ->val.array.typ->typ == TYPE_STRUCT_UNION) && typ->val.array.typ->val.st->has_incomplete) { - printf("Error: array types may not (inductively) point to structures which last element is incomplete\n"); + log_error(loginfo, "array types may not (inductively) point to structures which last element is incomplete\n"); return 0; } if ((typ->is_atomic) || (typ->is_const) || (typ->is_restrict) || (typ->is_volatile)) { // qualifier-type-list in array declaration is only allowed in function argument declaration under certain circumstances - printf("Error: array types may not be qualified\n"); + log_error(loginfo, "array types may not be qualified\n"); return 0; } - if (!validate_type(target, typ->val.array.typ)) return 0; + if (!validate_type(loginfo, target, typ->val.array.typ)) return 0; if (typ->val.array.array_sz == (size_t)-1) { typ->szinfo.size = 0; typ->szinfo.align = (typ->val.array.typ->szinfo.align < 16) ? 16 : typ->val.array.typ->szinfo.align; @@ -208,10 +279,10 @@ int validate_type(machine_t *target, type_t *typ) { case TYPE_PTR: typ->szinfo.size = target->size_long; typ->szinfo.align = target->size_long; - return validate_type(target, typ->val.typ); + return validate_type(loginfo, target, typ->val.typ); case TYPE_FUNCTION: if ((typ->val.fun.ret->typ == TYPE_FUNCTION) || (typ->val.fun.ret->typ == TYPE_ARRAY)) { - printf("Error: function types may not return function or array types\n"); + log_error(loginfo, "function types may not return function or array types\n"); return 0; } if (typ->val.fun.nargs != (size_t)-1) { @@ -219,57 +290,72 @@ int validate_type(machine_t *target, type_t *typ) { // Adjust the argument if necessary // Assume arrays are already converted if (typ->val.fun.args[i]->typ == TYPE_ARRAY) { - printf("Error: function argument %zu is an array\n", i + 1); + log_error(loginfo, "function argument %zu is an array\n", i + 1); return 0; } if (typ->val.fun.args[i]->typ == TYPE_FUNCTION) { // Adjustment to pointer type_t *t2 = type_new_ptr(typ->val.fun.args[i]); if (!t2) { - printf("Error: failed to adjust type of argument from function to pointer\n"); + log_error(loginfo, "failed to adjust type of argument from function to pointer\n"); return 0; } typ->val.fun.args[i] = t2; } - if (!validate_type(target, typ->val.fun.args[i])) return 0; + if (!validate_type(loginfo, target, typ->val.fun.args[i])) return 0; } } typ->szinfo.size = 0; typ->szinfo.align = 0; - return validate_type(target, typ->val.fun.ret); + return validate_type(loginfo, target, typ->val.fun.ret); case TYPE_STRUCT_UNION: { if (!typ->val.st->is_defined) return typ->is_incomplete; - size_t max_align = 1, cur_sz = 0, cur_bit = 0; + size_t max_align = 1, cur_sz = 0; unsigned char cur_bit = 0; for (size_t i = 0; i < typ->val.st->nmembers; ++i) { // Adjust the argument if necessary st_member_t *mem = &typ->val.st->members[i]; if (mem->typ->typ == TYPE_FUNCTION) { - printf("Error: structures may not contain function members\n"); + log_error(loginfo, "structures may not contain function members\n"); return 0; } if (mem->typ->is_incomplete) { if ((i != typ->val.st->nmembers - 1) || !typ->val.st->is_struct || (mem->typ->typ != TYPE_ARRAY)) { // The last element of a structure may be a VLA - printf("Error: structures may not contain incomplete members\n"); + log_error(loginfo, "structures may not contain incomplete members\n"); return 0; } typ->val.st->has_incomplete = 1; } - if (!validate_type(target, mem->typ)) return 0; + if (!validate_type(loginfo, target, mem->typ)) return 0; + if (!typ->val.st->has_self_recursion) fill_self_recursion(mem->typ, typ->val.st); if (!typ->val.st->is_struct && (mem->typ->typ == TYPE_STRUCT_UNION)) { typ->val.st->has_incomplete |= mem->typ->val.st->has_incomplete; + } else if ((mem->typ->typ == TYPE_STRUCT_UNION) && mem->typ->val.st->has_incomplete) { + log_error(loginfo, "structures may not (inductively) contain structures which last element is incomplete\n"); + return 0; + } else if (typ->val.st->is_struct) { + if (mem->typ->is_incomplete) { + if (i && (i == typ->val.st->nmembers - 1) && (mem->typ->typ == TYPE_ARRAY)) { + typ->val.st->has_incomplete |= mem->typ->val.st->has_incomplete; + } else { + log_error(loginfo, "structures may not have any incomplete element, except that the last, but not first, element may be an incomplete array\n"); + return 0; + } + } } + mem->byte_offset = cur_sz; + mem->bit_offset = cur_bit; if (mem->is_bitfield) { if (!typ->val.st->is_struct) { - printf("Error: TODO: bitfield in union\n"); + log_error(loginfo, "TODO: bitfield in union\n"); return 0; } if (mem->typ->is_atomic) { - printf("Error: atomic bitfields are not supported\n"); + log_error(loginfo, "atomic bitfields are not supported\n"); return 0; } if (mem->typ->typ != TYPE_BUILTIN) { - printf("Error: bitfields can only have a specific subset of types\n"); + log_error(loginfo, "bitfields can only have a specific subset of types\n"); return 0; } if ((mem->typ->val.builtin != BTT_BOOL) && (mem->typ->val.builtin != BTT_CHAR) @@ -285,11 +371,11 @@ int validate_type(machine_t *target, type_t *typ) { && (mem->typ->val.builtin != BTT_S64) && (mem->typ->val.builtin != BTT_U64)) { // C standard: allow _Bool, (s/u)int // Implementation: also allow (u/s)char, (u/s)short, (u/s)long, (u/s)long long, [u]intx_t - printf("Error: bitfields can only have a specific subset of types\n"); + log_error(loginfo, "bitfields can only have a specific subset of types\n"); return 0; } if (mem->typ->szinfo.size < mem->bitfield_width / 8) { - printf("Error: bitfield member %c%s%c has width (%zu) greater than its container size (%zu * 8)\n", + log_error(loginfo, "bitfield member %c%s%c has width (%zu) greater than its container size (%zu * 8)\n", mem->name ? '\'' : '<', mem->name ? string_content(mem->name) : "unnamed", mem->name ? '\'' : '>', @@ -302,7 +388,8 @@ int validate_type(machine_t *target, type_t *typ) { size_t cur_block = cur_sz / mem->typ->szinfo.align; size_t end_block = (cur_sz + (cur_bit + mem->bitfield_width - 1) / 8) / mem->typ->szinfo.align; if (cur_block == end_block) { - cur_bit += mem->bitfield_width; + cur_sz += mem->bitfield_width / 8; + cur_bit += mem->bitfield_width % 8; cur_sz += cur_bit / 8; cur_bit %= 8; } else { @@ -312,7 +399,7 @@ int validate_type(machine_t *target, type_t *typ) { } else { if (max_align < mem->typ->szinfo.align) max_align = mem->typ->szinfo.align; cur_sz = ((cur_sz + mem->typ->szinfo.align - 1) & ~(mem->typ->szinfo.align - 1)) + mem->typ->szinfo.size; - printf("Error: TODO: unnamed zero-width bitfield member\n"); + log_error(loginfo, "TODO: unnamed zero-width bitfield member\n"); return 0; } } else { @@ -337,7 +424,7 @@ int validate_type(machine_t *target, type_t *typ) { return 1; } case TYPE_ENUM: if (typ->val.typ->typ != TYPE_BUILTIN) { - printf("Error: the underlying type of an enum is not a builtin type\n"); + log_error(loginfo, "the underlying type of an enum is not a builtin type\n"); return 0; } typ->szinfo = typ->val.typ->szinfo; diff --git a/wrapperhelper/src/machine.h b/wrapperhelper/src/machine.h index 566f1d435..67867c709 100644 --- a/wrapperhelper/src/machine.h +++ b/wrapperhelper/src/machine.h @@ -5,6 +5,7 @@ #include "cstring.h" #include "khash.h" +#include "log.h" #include "vector.h" struct type_s; // lang.h @@ -16,7 +17,9 @@ typedef struct machine_s { // Parsing size_t size_long; + size_t align_longdouble, size_longdouble; size_t align_valist, size_valist; + size_t max_align; _Bool has_int128; _Bool unsigned_char; // Structure parsing _Bool unnamed_bitfield_aligns; @@ -26,6 +29,6 @@ int init_machines(size_t npaths, const char *const *extra_include_path); void del_machines(void); machine_t *convert_machine_name(const char *archname); -int validate_type(machine_t *target, struct type_s *typ); +int validate_type(loginfo_t *loginfo, machine_t *target, struct type_s *typ); #endif // MACHINE_H diff --git a/wrapperhelper/src/main.c b/wrapperhelper/src/main.c index efa410ab4..14a67ce62 100644 --- a/wrapperhelper/src/main.c +++ b/wrapperhelper/src/main.c @@ -12,8 +12,8 @@ static void help(char *arg0) { printf("Usage: %s --help\n" - " %s {-I/path/to/include}* [--prepare|--preproc|--proc] [--arch ] \n" - " %s {-I/path/to/include}* [--emu ] [--target ] \n" + " %s {-I/path/to/include}* [--prepare|--preproc|--proc] [--arch |-32|-64|--32|--64] \n" + " %s {-I/path/to/include}* [[--emu ] [--target ]|-32|-64|--32|--64] \n" "\n" " --prepare Dump all preprocessor tokens (prepare phase)\n" " --preproc Dump all processor tokens (preprocessor phase)\n" @@ -29,8 +29,10 @@ static void help(char *arg0) { " --arch Use the architecture \n" " --emu Use the architecture as emulated architecture\n" " --target Use the architecture as target/running architecture\n" + " -32 --32 Use the x86 architecture as arch/emulated, aarch64 as target\n" + " -64 --64 Use the x86_64 architecture as arch/emulated, aarch64 as target\n" "\n" - " is one of 'x86_64', 'aarch64'\n", + " is one of 'x86', 'x86_64', 'aarch64'\n", arg0, arg0, arg0); } @@ -41,14 +43,21 @@ enum main_state { MAIN_PROC, }; +enum bits_state { + BITS_NONE, + BITS_32, + BITS_64, +}; + int main(int argc, char **argv) { setbuf(stdout, NULL); if (!setlocale(LC_NUMERIC, "C")) { - printf("Error: failed to set LC_NUMERIC to C\n"); + log_error_nopos("failed to set LC_NUMERIC to C\n"); return 2; } enum main_state ms = MAIN_RUN; + enum bits_state bs = BITS_NONE; const char *in_file = NULL, *ref_file = NULL, *out_file = NULL; VECTOR(charp) *paths = vector_new(charp); const char *archname = NULL, *emuname = NULL, *targetname = NULL; @@ -69,13 +78,13 @@ int main(int argc, char **argv) { // Ignore } else if (!strcmp(argv[i], "-I") && (i + 1 < argc)) { if (!vector_push(charp, paths, argv[i + 1])) { - printf("Error: failed to add path to buffer\n"); + log_memory("failed to add path to buffer\n"); return 2; } ++i; } else if ((argv[i][0] == '-') && (argv[i][1] == 'I') && (argv[i][2] != '\0')) { if (!vector_push(charp, paths, argv[i] + 2)) { - printf("Error: failed to add path to buffer\n"); + log_memory("failed to add path to buffer\n"); return 2; } } else if (!strcmp(argv[i], "--arch")) { @@ -83,7 +92,7 @@ int main(int argc, char **argv) { if (i < argc) { archname = argv[i]; } else { - printf("Error: invalid '--arch' option in last position\n"); + log_error_nopos("invalid '--arch' option in last position\n"); help(argv[0]); return 0; } @@ -92,7 +101,7 @@ int main(int argc, char **argv) { if (i < argc) { emuname = argv[i]; } else { - printf("Error: invalid '--emu' option in last position\n"); + log_error_nopos("invalid '--emu' option in last position\n"); help(argv[0]); return 0; } @@ -101,16 +110,20 @@ int main(int argc, char **argv) { if (i < argc) { targetname = argv[i]; } else { - printf("Error: invalid '--target' option in last position\n"); + log_error_nopos("invalid '--target' option in last position\n"); help(argv[0]); return 0; } + } else if (!strcmp(argv[i], "-32") || !strcmp(argv[i], "--32")) { + bs = BITS_32; + } else if (!strcmp(argv[i], "-64") || !strcmp(argv[i], "--64")) { + bs = BITS_64; } else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--filename")) { ++i; if (i < argc) { isfile = 1; } else { - printf("Error: invalid '--filename' option in last position\n"); + log_error_nopos("invalid '--filename' option in last position\n"); help(argv[0]); return 0; } @@ -125,7 +138,7 @@ int main(int argc, char **argv) { } else if (!out_file) { out_file = argv[i]; } else { - printf("Error: too many unknown options considered as file\n"); + log_error_nopos("too many unknown options considered as file\n"); help(argv[0]); return 2; } @@ -137,15 +150,23 @@ int main(int argc, char **argv) { case MAIN_PROC: check_proc: if (!in_file || ref_file || out_file) { - printf("Error: too many unknown options/not enough arguments\n"); + log_error_nopos("too many unknown options/not enough arguments\n"); help(argv[0]); return 2; } if (emuname || targetname) { - printf("Error: invalid option '--emu' or '--target' in prepare/preprocessor/processor mode\n"); + log_error_nopos("invalid option '--emu' or '--target' in prepare/preprocessor/processor mode\n"); help(argv[0]); return 2; } + if (bs != BITS_NONE) { + if (archname) { + log_error_nopos("invalid option '--arch' with '--32' or '--64' in prepare/preprocessor/processor mode\n"); + help(argv[0]); + return 2; + } + archname = (bs == BITS_32) ? "x86" : "x86_64"; + } if (!archname) archname = "x86_64"; break; case MAIN_RUN: @@ -154,15 +175,24 @@ int main(int argc, char **argv) { goto check_proc; } if (!in_file || !ref_file || !out_file) { - printf("Error: too many unknown options/not enough arguments\n"); + log_error_nopos("too many unknown options/not enough arguments\n"); help(argv[0]); return 2; } if (archname) { - printf("Error: invalid option '--arch' in run mode\n"); + log_error_nopos("invalid option '--arch' in run mode\n"); help(argv[0]); return 2; } + if (bs != BITS_NONE) { + if (emuname || targetname) { + log_error_nopos("invalid option '--emu' or '--target' with '--32' or '--64' in run mode\n"); + help(argv[0]); + return 2; + } + emuname = (bs == BITS_32) ? "x86" : "x86_64"; + targetname = "aarch64"; + } if (!emuname) emuname = "x86_64"; if (!targetname) targetname = "aarch64"; break; @@ -173,6 +203,7 @@ int main(int argc, char **argv) { } if (!init_machines(vector_size(charp, paths), (const char*const*)vector_content(charp, paths))) { vector_del(charp, paths); + del_str2kw(); return 2; } vector_del(charp, paths); @@ -180,22 +211,30 @@ int main(int argc, char **argv) { FILE *f = fopen(in_file, "r"); if (!f) { err(2, "Error: failed to open %s", in_file); + del_machines(); + del_str2kw(); return 2; } switch (ms) { case MAIN_RUN: { machine_t *emu = convert_machine_name(emuname); if (!emu) { - printf("Error: invalid emulation architecture '%s'\n", emuname); + log_error_nopos("invalid emulation architecture '%s'\n", emuname); + del_machines(); + del_str2kw(); + return 0; } machine_t *target = convert_machine_name(targetname); if (!target) { - printf("Error: invalid target architecture '%s'\n", targetname); + log_error_nopos("invalid target architecture '%s'\n", targetname); + del_machines(); + del_str2kw(); + return 0; } file_t *emu_content = parse_file(emu, in_file, f); // Takes ownership of f if (!emu_content) { - printf("Error: failed to parse the file\n"); + log_error_nopos("failed to parse the file\n"); del_machines(); del_str2kw(); return 0; @@ -204,11 +243,14 @@ int main(int argc, char **argv) { f = fopen(in_file, "r"); if (!f) { err(2, "Error: failed to re-open %s", in_file); + file_del(emu_content); + del_machines(); + del_str2kw(); return 2; } file_t *target_content = parse_file(target, in_file, f); // Takes ownership of f if (!target_content) { - printf("Error: failed to parse the file\n"); + log_error_nopos("failed to parse the file\n"); file_del(emu_content); del_machines(); del_str2kw(); @@ -218,6 +260,8 @@ int main(int argc, char **argv) { FILE *ref = fopen(ref_file, "r"); if (!ref) { err(2, "Error: failed to open %s", ref_file); + file_del(emu_content); + file_del(target_content); del_machines(); del_str2kw(); return 2; @@ -231,8 +275,14 @@ int main(int argc, char **argv) { return 2; } // vector_for(references, req, refs) request_print(req); - if (!solve_references(refs, emu_content->decl_map, target_content->decl_map, emu_content->relaxed_type_conversion)) { - printf("Warning: failed to solve all default requests\n"); + if (target->size_long != emu->size_long) { + if (!solve_references(refs, emu_content->decl_map, target_content->decl_map, emu_content->relaxed_type_conversion)) { + log_warning_nopos("failed to solve all default requests\n"); + } + } else { + if (!solve_references_simple(refs, emu_content->decl_map, target_content->decl_map, emu_content->relaxed_type_conversion)) { + log_warning_nopos("failed to solve all default requests\n"); + } } // vector_for(references, req, refs) request_print(req); references_print_check(refs); @@ -254,14 +304,15 @@ int main(int argc, char **argv) { del_machines(); del_str2kw(); return 0; } + case MAIN_PROC: { machine_t *arch = convert_machine_name(archname); if (!arch) { - printf("Error: invalid architecture '%s'\n", archname); + log_error_nopos("invalid architecture '%s'\n", archname); } file_t *content = parse_file(arch, in_file, f); // Takes ownership of f if (!content) { - printf("Error: failed to parse the file\n"); + log_error_nopos("failed to parse the file\n"); del_machines(); del_str2kw(); return 0; @@ -334,7 +385,7 @@ int main(int argc, char **argv) { case MAIN_PREPROC: { machine_t *arch = convert_machine_name(archname); if (!arch) { - printf("Error: invalid architecture '%s'\n", archname); + log_error_nopos("invalid architecture '%s'\n", archname); } dump_preproc(arch, in_file, f); // Takes ownership of f del_machines(); @@ -342,6 +393,6 @@ int main(int argc, char **argv) { return 0; } } - printf("Internal error: failed to run mode %u\n", ms); + log_internal_nopos("failed to run mode %u\n", ms); return 2; } diff --git a/wrapperhelper/src/parse.c b/wrapperhelper/src/parse.c index 0254d8df2..8f593f22e 100644 --- a/wrapperhelper/src/parse.c +++ b/wrapperhelper/src/parse.c @@ -12,7 +12,7 @@ void dump_prepare(const char *filename, FILE *file) { prepare_t *prep = prepare_new_file(file, filename); if (!prep) { - printf("Failed to create the prepare structure\n"); + log_memory("failed to create the prepare structure\n"); return; } while (1) { @@ -30,7 +30,7 @@ void dump_preproc(machine_t *target, const char *filename, FILE *file) { char *dirname = strchr(filename, '/') ? strndup(filename, (size_t)(strrchr(filename, '/') - filename)) : NULL; preproc_t *prep = preproc_new_file(target, file, dirname, filename); if (!prep) { - printf("Failed to create the preproc structure\n"); + log_memory("failed to create the preproc structure\n"); if (dirname) free(dirname); return; } @@ -90,29 +90,31 @@ VECTOR_IMPL_STATIC(size_t, (void)) #define VALIDATION_DECL 1 #define VALIDATION_LAST_DECL 2 #define VALIDATION_FUN 3 -static int validate_storage_type(machine_t *target, enum decl_storage storage, +static int validate_storage_type(loginfo_t *loginfo, machine_t *target, enum decl_storage storage, type_t *typ, enum token_sym_type_e sym) { // We may still do adjustments here - if (!validate_type(target, typ)) return 0; + if (!validate_type(loginfo, target, typ)) return 0; if (typ->typ == TYPE_FUNCTION) { if ((storage == TMPSTO_TLS) || (storage == TMPSTO_TLS_EXTERN) || (storage == TMPSTO_TLS_STATIC)) { - printf("Error: functions cannot be thread local\n"); + log_error(loginfo, "functions cannot be thread local\n"); return 0; } if ((sym == SYM_COMMA) || (sym == SYM_RPAREN) || (sym == SYM_SEMICOLON)) { return (sym == SYM_SEMICOLON) ? VALIDATION_LAST_DECL : VALIDATION_DECL; } else if (sym == SYM_LBRACKET) { return VALIDATION_FUN; + } else { + log_error(loginfo, "unexpected symbol %s (%u) after function declaration\n", sym2str[sym], sym); + return 0; } } else { if ((sym == SYM_COMMA) || (sym == SYM_RPAREN) || (sym == SYM_SEMICOLON) || ((storage != TMPSTO_TYPEDEF) && (sym == SYM_EQ))) { return (sym == SYM_SEMICOLON) ? VALIDATION_LAST_DECL : VALIDATION_DECL; + } else { + log_error(loginfo, "unexpected symbol %s (%u) after %s declaration\n", sym2str[sym], sym, (storage == TMPSTO_TYPEDEF) ? "type" : "variable"); + return 0; } } - printf("TODO: validate_storage_type on storage %u, sym %s (%u), valid type ", storage, sym2str[sym], sym); - type_print(typ); - printf("\n"); - return 0; } static void promote_csts(num_constant_t *v1, num_constant_t *v2) { @@ -197,6 +199,8 @@ static void promote_csts(num_constant_t *v1, num_constant_t *v2) { } } +#define TOKEN_MATCH_ATTR(attr) (!strcmp(string_content(tok->tokv.str), #attr) || !strcmp(string_content(tok->tokv.str), "__" #attr "__")) + VECTOR_DECLARE_STATIC(exprs, expr_t*) #define expr_del_ptr(p) expr_del(*(p)) VECTOR_IMPL_STATIC(exprs, expr_del_ptr) @@ -310,95 +314,6 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s type_t *(*builtins)[LAST_BUILTIN + 1], khash_t(const_map) *const_map, khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, enum decl_storage *storage, enum fun_spec *fspec, enum decl_spec *spec, type_t *typ); - -void expr_print(expr_t *e) { - switch (e->typ) { - case ETY_VAR: printf("%s", string_content(e->val.var)); break; - case ETY_CONST: - switch (e->val.cst.typ) { - case NCT_FLOAT: printf("%ff", e->val.cst.val.f); break; - case NCT_DOUBLE: printf("%f", e->val.cst.val.d); break; - case NCT_LDOUBLE: printf("%Lfl", e->val.cst.val.l); break; - case NCT_INT32: printf("%d", e->val.cst.val.i32); break; - case NCT_UINT32: printf("%uu", e->val.cst.val.u32); break; - case NCT_INT64: printf("%ldll", e->val.cst.val.i64); break; - case NCT_UINT64: printf("%lullu", e->val.cst.val.u64); break; - } - break; - case ETY_CALL: printf("(call)"); break; - case ETY_ACCESS: printf("(.)"); break; - case ETY_PTRACCESS: printf("(->)"); break; - case ETY_UNARY: - switch (e->val.unary.typ) { - case UOT_POSTINCR: printf("(++)"); expr_print(e->val.unary.e); break; - case UOT_POSTDECR: printf("(--)"); expr_print(e->val.unary.e); break; - case UOT_PREINCR: printf("++"); expr_print(e->val.unary.e); break; - case UOT_PREDECR: printf("--"); expr_print(e->val.unary.e); break; - case UOT_REF: printf("&"); expr_print(e->val.unary.e); break; - case UOT_POS: printf("(+)"); expr_print(e->val.unary.e); break; - case UOT_NEG: printf("(-)"); expr_print(e->val.unary.e); break; - case UOT_DEREF: printf("(*)"); expr_print(e->val.unary.e); break; - case UOT_ANOT: printf("~"); expr_print(e->val.unary.e); break; - case UOT_BNOT: printf("!"); expr_print(e->val.unary.e); break; - } - break; - case ETY_BINARY: { - printf("("); - expr_print(e->val.binary.e1); - switch (e->val.binary.typ) { - case BOT_ADD: printf(") + ("); break; - case BOT_SUB: printf(") - ("); break; - case BOT_MUL: printf(") * ("); break; - case BOT_DIV: printf(") / ("); break; - case BOT_MOD: printf(") %% ("); break; - case BOT_LSH: printf(") << ("); break; - case BOT_RSH: printf(") >> ("); break; - case BOT_LT: printf(") < ("); break; - case BOT_GT: printf(") > ("); break; - case BOT_LE: printf(") <= ("); break; - case BOT_GE: printf(") >= ("); break; - case BOT_EQ: printf(") == ("); break; - case BOT_NE: printf(") != ("); break; - case BOT_AAND: printf(") & ("); break; - case BOT_AXOR: printf(") ^ ("); break; - case BOT_AOR: printf(") | ("); break; - case BOT_BAND: printf(") && ("); break; - case BOT_BOR: printf(") || ("); break; - case BOT_ASSGN_EQ: printf(") = ("); break; - case BOT_ASSGN_ADD: printf(") += ("); break; - case BOT_ASSGN_SUB: printf(") -= ("); break; - case BOT_ASSGN_MUL: printf(") *= ("); break; - case BOT_ASSGN_DIV: printf(") /= ("); break; - case BOT_ASSGN_MOD: printf(") %%= ("); break; - case BOT_ASSGN_LSH: printf(") <<= ("); break; - case BOT_ASSGN_RSH: printf(") >>= ("); break; - case BOT_ASSGN_AAND: printf(") &= ("); break; - case BOT_ASSGN_AXOR: printf(") ^= ("); break; - case BOT_ASSGN_AOR: printf(") |= ("); break; - case BOT_COMMA: printf("), ("); break; - case BOT_ARRAY: printf(")["); break; - } - expr_print(e->val.binary.e2); - printf(e->val.binary.typ == BOT_ARRAY ? "]" : ")"); - break; } - case ETY_TERNARY: { - printf("("); - expr_print(e->val.ternary.e1); - switch (e->val.ternary.typ) { - case TOT_COND: printf(") ? "); break; - } - expr_print(e->val.ternary.e2); - switch (e->val.ternary.typ) { - case TOT_COND: printf(" : ("); break; - } - expr_print(e->val.ternary.e3); - printf(")"); - break; } - case ETY_CAST: printf("("); type_print(e->val.cast.typ); printf(")"); expr_print(e->val.cast.e); break; - } -} - - static int is_type_spec_qual_kw(enum token_keyword_type_e kw) { return (kw == KW_ATOMIC) || @@ -437,7 +352,7 @@ static int parse_type_name(machine_t *target, khash_t(struct_map) *struct_map, k } *typ = type_try_merge(*typ, type_set); if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == end_sym)) { - return validate_type(target, *typ); + return validate_type(&tok->loginfo, target, *typ); } struct parse_declarator_dest_s dest2; dest2.argt.dest = NULL; @@ -454,18 +369,20 @@ static int parse_type_name(machine_t *target, khash_t(struct_map) *struct_map, k } type_del(*typ); if (!dest2.argt.dest) { - printf("Internal error: argument type is NULL\n"); + log_internal(&tok->loginfo, "parse_type_name: argument type is NULL\n"); // Empty destructor goto failed; } if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != end_sym)) { + log_error(&tok->loginfo, "invalid token %s %u after type name\n", + (tok->tokt == PTOK_SYM) ? "symbol" : "type", (tok->tokt == PTOK_SYM) ? tok->tokv.sym : tok->tokt); type_del(dest2.argt.dest); proc_token_del(tok); goto failed; } *typ = dest2.argt.dest; *typ = type_try_merge(*typ, type_set); - return validate_type(target, *typ); + return validate_type(&tok->loginfo, target, *typ); failed: return 0; @@ -476,13 +393,13 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, int expr_level) { // Note that expr_level >= 1; expr_level = 0 doesn't appear in the grammar if ((expr_level < 1) || (expr_level > 16)) { - printf("Internal error: invalid expression level %d\n", expr_level); + log_internal(&tok->loginfo, "Internal error: invalid expression level %d\n", expr_level); return NULL; } VECTOR(expr_pops) *op_stack = vector_new(expr_pops); if (!op_stack) { - printf("Error: failed to create operation stack"); + log_memory("failed to create operation stack"); proc_token_del(tok); return NULL; } @@ -494,18 +411,16 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m e = NULL; expr_new_token: - // printf("expr_new_token with level %d / %d\n", has_level, expr_level); - // proc_token_print(tok); if (tok->tokt == PTOK_IDENT) { if (has_level != -1) { - printf("Error: invalid expression: unexpected identifier '%s'\n", string_content(tok->tokv.str)); + log_error(&tok->loginfo, "invalid expression: unexpected identifier '%s'\n", string_content(tok->tokv.str)); string_del(tok->tokv.str); goto failed; } has_level = 0; e = malloc(sizeof *e); if (!e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); string_del(tok->tokv.str); goto failed; } @@ -515,19 +430,19 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto expr_new_token; } else if (tok->tokt == PTOK_NUM) { if (has_level != -1) { - printf("Error: invalid expression: unexpected number '%s'\n", string_content(tok->tokv.str)); + log_error(&tok->loginfo, "invalid expression: unexpected number '%s'\n", string_content(tok->tokv.str)); string_del(tok->tokv.str); goto failed; } has_level = 0; e = malloc(sizeof *e); if (!e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); string_del(tok->tokv.str); goto failed; } e->typ = ETY_CONST; - if (!num_constant_convert(tok->tokv.str, &e->val.cst, target->size_long == 4)) { + if (!num_constant_convert(&tok->loginfo, tok->tokv.str, &e->val.cst, target->size_long == 4)) { string_del(tok->tokv.str); goto failed; } @@ -536,19 +451,19 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto expr_new_token; } else if ((tok->tokt == PTOK_STRING) && !tok->tokv.sisstr) { if (has_level != -1) { - printf("Error: invalid expression: unexpected character constant '%s'\n", string_content(tok->tokv.sstr)); + log_error(&tok->loginfo, "invalid expression: unexpected character constant '%s'\n", string_content(tok->tokv.sstr)); string_del(tok->tokv.sstr); goto failed; } if (string_len(tok->tokv.sstr) != 1) { - printf("Error: TODO: invalid expression: multibyte character constant '%s'\n", string_content(tok->tokv.sstr)); + log_TODO(&tok->loginfo, "invalid expression: multibyte character constant '%s'\n", string_content(tok->tokv.sstr)); string_del(tok->tokv.sstr); goto failed; } has_level = 0; e = malloc(sizeof *e); if (!e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); string_del(tok->tokv.sstr); goto failed; } @@ -570,7 +485,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.unop = opt \ }; \ if (!vector_push(expr_pops, op_stack, pop)) { \ - printf("Error: failed to add partial operation to operation stack\n"); \ + log_memory("failed to add partial operation to operation stack\n"); \ /* Empty destructor */ \ goto failed; \ } \ @@ -589,7 +504,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.binop = {.op = opt, .e1 = e} \ }; \ if (!vector_push(expr_pops, op_stack, pop)) { \ - printf("Error: failed to add partial operation to operation stack\n"); \ + log_memory("failed to add partial operation to operation stack\n"); \ /* Empty destructor */ \ goto failed; \ } \ @@ -598,12 +513,13 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto pushed_expr; \ } \ } + if ((expr_level >= 1) && (tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_PLUSPLUS)) { if ((has_level != -1) && (has_level <= 1)) { has_level = 1; expr_t *new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); string_del(tok->tokv.str); goto failed; } @@ -620,7 +536,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m has_level = 1; expr_t *new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); string_del(tok->tokv.str); goto failed; } @@ -641,7 +557,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.binop = {.last_sym = SYM_RSQBRACKET, .op = BOT_ARRAY, .e1 = e} }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); /* Empty destructor */ goto failed; } @@ -657,13 +573,13 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m *tok = proc_next_token(prep); if (tok->tokt != PTOK_IDENT) { - printf("Error: invalid expression: unexpected token after access symbol\n"); + log_error(&tok->loginfo, "invalid expression: unexpected token after access symbol\n"); proc_token_del(tok); goto failed; } expr_t *new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); string_del(tok->tokv.str); goto failed; } @@ -683,24 +599,24 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m UNOP(SYM_STAR, UOT_DEREF, 2, 3) UNOP(SYM_TILDE, UOT_ANOT, 2, 3) UNOP(SYM_EXCL, UOT_BNOT, 2, 3) - BINOP(SYM_STAR, BOT_MUL, 4, 4, 3) - BINOP(SYM_SLASH, BOT_DIV, 4, 4, 3) - BINOP(SYM_PERCENT, BOT_MOD, 4, 4, 3) - BINOP(SYM_PLUS, BOT_ADD, 5, 5, 4) - BINOP(SYM_DASH, BOT_SUB, 5, 5, 4) - BINOP(SYM_LTLT, BOT_LSH, 6, 6, 5) - BINOP(SYM_GTGT, BOT_RSH, 6, 6, 5) - BINOP(SYM_LT, BOT_LT, 7, 7, 6) - BINOP(SYM_GT, BOT_GT, 7, 7, 6) - BINOP(SYM_LTEQ, BOT_LE, 7, 7, 6) - BINOP(SYM_GTEQ, BOT_GE, 7, 7, 6) - BINOP(SYM_EQEQ, BOT_EQ, 8, 8, 7) - BINOP(SYM_EXCLEQ, BOT_NE, 8, 8, 7) - BINOP(SYM_AMP, BOT_AAND, 9, 9, 8) - BINOP(SYM_HAT, BOT_AXOR, 10, 10, 9) - BINOP(SYM_PIPE, BOT_AOR, 11, 11, 10) - BINOP(SYM_AMPAMP, BOT_BAND, 12, 12, 11) - BINOP(SYM_PIPEPIPE, BOT_BOR, 13, 13, 12) + BINOP(SYM_STAR, BOT_MUL, 4, 4, 3) + BINOP(SYM_SLASH, BOT_DIV, 4, 4, 3) + BINOP(SYM_PERCENT, BOT_MOD, 4, 4, 3) + BINOP(SYM_PLUS, BOT_ADD, 5, 5, 4) + BINOP(SYM_DASH, BOT_SUB, 5, 5, 4) + BINOP(SYM_LTLT, BOT_LSH, 6, 6, 5) + BINOP(SYM_GTGT, BOT_RSH, 6, 6, 5) + BINOP(SYM_LT, BOT_LT, 7, 7, 6) + BINOP(SYM_GT, BOT_GT, 7, 7, 6) + BINOP(SYM_LTEQ, BOT_LE, 7, 7, 6) + BINOP(SYM_GTEQ, BOT_GE, 7, 7, 6) + BINOP(SYM_EQEQ, BOT_EQ, 8, 8, 7) + BINOP(SYM_EXCLEQ, BOT_NE, 8, 8, 7) + BINOP(SYM_AMP, BOT_AAND, 9, 9, 8) + BINOP(SYM_HAT, BOT_AXOR, 10, 10, 9) + BINOP(SYM_PIPE, BOT_AOR, 11, 11, 10) + BINOP(SYM_AMPAMP, BOT_BAND, 12, 12, 11) + BINOP(SYM_PIPEPIPE, BOT_BOR, 13, 13, 12) if ((expr_level >= 14) && (tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) { if ((has_level != -1) && (has_level <= 13)) { struct expr_partial_op pop = { @@ -710,7 +626,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.ternop = {.arg23_sep = SYM_COLON, .once_done2_want_level = 14, .op = TOT_COND, .e1 = e} }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); // Empty destructor goto failed; } @@ -719,18 +635,18 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto pushed_expr; } } - BINOP(SYM_EQ, BOT_ASSGN_EQ, 15, 2, 15) - BINOP(SYM_STAREQ, BOT_ASSGN_MUL, 15, 2, 15) - BINOP(SYM_SLASHEQ, BOT_ASSGN_DIV, 15, 2, 15) - BINOP(SYM_PERCENTEQ, BOT_ASSGN_MOD, 15, 2, 15) - BINOP(SYM_PLUSEQ, BOT_ASSGN_ADD, 15, 2, 15) - BINOP(SYM_DASHEQ, BOT_ASSGN_SUB, 15, 2, 15) - BINOP(SYM_LTLTEQ, BOT_ASSGN_LSH, 15, 2, 15) - BINOP(SYM_GTGTEQ, BOT_ASSGN_RSH, 15, 2, 15) - BINOP(SYM_AMPEQ, BOT_ASSGN_AAND, 15, 2, 15) - BINOP(SYM_HATEQ, BOT_ASSGN_AXOR, 15, 2, 15) - BINOP(SYM_PIPEEQ, BOT_ASSGN_AOR, 15, 2, 15) - BINOP(SYM_COMMA, BOT_COMMA, 16, 16, 15) + BINOP(SYM_EQ, BOT_ASSGN_EQ, 15, 2, 15) + BINOP(SYM_STAREQ, BOT_ASSGN_MUL, 15, 2, 15) + BINOP(SYM_SLASHEQ, BOT_ASSGN_DIV, 15, 2, 15) + BINOP(SYM_PERCENTEQ, BOT_ASSGN_MOD, 15, 2, 15) + BINOP(SYM_PLUSEQ, BOT_ASSGN_ADD, 15, 2, 15) + BINOP(SYM_DASHEQ, BOT_ASSGN_SUB, 15, 2, 15) + BINOP(SYM_LTLTEQ, BOT_ASSGN_LSH, 15, 2, 15) + BINOP(SYM_GTGTEQ, BOT_ASSGN_RSH, 15, 2, 15) + BINOP(SYM_AMPEQ, BOT_ASSGN_AAND, 15, 2, 15) + BINOP(SYM_HATEQ, BOT_ASSGN_AXOR, 15, 2, 15) + BINOP(SYM_PIPEEQ, BOT_ASSGN_AOR, 15, 2, 15) + BINOP(SYM_COMMA, BOT_COMMA, 16, 16, 15) // expr2 ::= sizeof expr2 // which includes expr2 ::= sizeof ( expr16 ) @@ -745,7 +661,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.c = '\0' }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); proc_token_del(tok); goto failed; } @@ -758,7 +674,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m if (IS_BEGIN_TYPE_NAME) { type_t *typ = type_new(); if (!typ) { - printf("Error: failed to create new type info structure\n"); + log_memory("failed to create new type info structure\n"); proc_token_del(tok); goto failed; } @@ -766,14 +682,14 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto failed; } if (!typ->is_validated || typ->is_incomplete || (typ->typ == TYPE_FUNCTION)) { - printf("Error: cannot get the size of a function or incomplete type\n"); + log_error(&tok->loginfo, "cannot get the size of a function or incomplete type\n"); type_del(typ); proc_token_del(tok); goto failed; } e = malloc(sizeof *e); if (!e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); type_del(typ); proc_token_del(tok); goto failed; @@ -784,6 +700,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m has_level = 2; type_del(typ); if (!e->val.cst.val.u64) { + log_internal(&tok->loginfo, "size of type is 0\n"); proc_token_del(tok); goto failed; } @@ -798,7 +715,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.c = 0 }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); proc_token_del(tok); goto failed; } @@ -809,7 +726,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.c = 0 }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); proc_token_del(tok); goto failed; } @@ -821,7 +738,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m if ((has_level == -1) && (expr_level >= 2) && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ALIGNOF)) { *tok = proc_next_token(prep); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) { - printf("Error: invalid _Alignof expression\n"); + log_error(&tok->loginfo, "unexpected token, expected symbol '('\n"); proc_token_del(tok); goto failed; } @@ -829,7 +746,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m *tok = proc_next_token(prep); type_t *typ = type_new(); if (!typ) { - printf("Error: failed to create new type info structure\n"); + log_memory("failed to create new type info structure\n"); proc_token_del(tok); goto failed; } @@ -837,14 +754,14 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto failed; } if (!typ->is_validated || typ->is_incomplete || (typ->typ == TYPE_FUNCTION)) { - printf("Error: cannot get the alignment of a function or incomplete type\n"); + log_error(&tok->loginfo, "cannot get the alignment of a function or incomplete type\n"); type_del(typ); proc_token_del(tok); goto failed; } e = malloc(sizeof *e); if (!e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); type_del(typ); proc_token_del(tok); goto failed; @@ -855,6 +772,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m has_level = 2; type_del(typ); if (!e->val.cst.val.u64) { + log_internal(&tok->loginfo, "alignment of type is 0\n"); proc_token_del(tok); goto failed; } @@ -876,7 +794,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m expr_t *new_e = malloc(sizeof *new_e); new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); // Empty destructor goto failed; } @@ -891,7 +809,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m // We want a function call with at least one argument VECTOR(exprs) *exprs = vector_new_cap(exprs, 1); if (!exprs) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); proc_token_del(tok); goto failed; } @@ -902,7 +820,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.funcall = {.f = e, .exprs = exprs} }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); vector_del(exprs, exprs); proc_token_del(tok); goto failed; @@ -916,7 +834,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m if ((expr_level >= 1) && IS_BEGIN_TYPE_NAME) { type_t *typ = type_new(); if (!typ) { - printf("Error: failed to create new type info structure\n"); + log_memory("failed to create new type info structure\n"); proc_token_del(tok); goto failed; } @@ -926,12 +844,12 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto failed; } if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_LBRACKET)) { - printf("Error: TODO: initializer-list\n"); + log_TODO(&tok->loginfo, "initializer-list\n"); type_del(typ); proc_token_del(tok); goto failed; } else if (expr_level < 3) { - printf("Error: cast expression (level 3) but the expression level is at most 2\n"); + log_error(&tok->loginfo, "cast expression (level 3) but the required expression level is 1 or 2 (expected symbol '{')\n"); type_del(typ); proc_token_del(tok); goto failed; @@ -943,7 +861,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.typ = typ }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); /* Empty destructor */ goto failed; } @@ -959,7 +877,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m .val.c = 0 }; if (!vector_push(expr_pops, op_stack, pop)) { - printf("Error: failed to add partial operation to operation stack\n"); + log_memory("failed to add partial operation to operation stack\n"); proc_token_del(tok); goto failed; } @@ -985,13 +903,13 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m } break; case EPO_SIZEOF: - printf("Error: TODO: find type of expression\n"); + log_TODO(&tok->loginfo, "find type of expression\n"); proc_token_del(tok); goto failed; case EPO_CAST: new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); proc_token_del(tok); goto failed; } @@ -1009,13 +927,13 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m has_level = pop->once_done_is_level; expr_level = pop->once_done_want_level; if (!vector_push(exprs, pop->val.funcall.exprs, e)) { - printf("Error: failed to add argument to argument stack\n"); + log_memory("failed to add argument to argument stack\n"); // Empty destructor goto failed; } e = malloc(sizeof *e); if (!e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); // Empty destructor goto failed; } @@ -1029,7 +947,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m goto expr_new_token; } else if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_COMMA)) { if (!vector_push(exprs, pop->val.funcall.exprs, e)) { - printf("Error: failed to add argument to argument stack\n"); + log_memory("failed to add argument to argument stack\n"); // Empty destructor goto failed; } @@ -1042,7 +960,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m case EPO_UNARY: new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); proc_token_del(tok); goto failed; } @@ -1063,7 +981,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m case EPO_BINARY_ARG: new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); proc_token_del(tok); goto failed; } @@ -1090,7 +1008,7 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m case EPO_TERNARY_ARG2: new_e = malloc(sizeof *new_e); if (!new_e) { - printf("Error: failed to create new expression atom\n"); + log_memory("failed to create new expression atom\n"); proc_token_del(tok); goto failed; } @@ -1113,15 +1031,14 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m vector_del(expr_pops, op_stack); return e; } - printf("Error: invalid expression: unexpected token\n"); - proc_token_print(tok); + log_error(&tok->loginfo, "invalid expression: unexpected token\n"); proc_token_del(tok); failed: vector_del(expr_pops, op_stack); if (e) expr_del(e); return NULL; } -static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constant_t *dest, int fatal) { +static int eval_expression(loginfo_t *li, machine_t *target, expr_t *e, khash_t(const_map) *const_map, num_constant_t *dest, int fatal) { // Evaluate the expression (we suppose it is constant) switch (e->typ) { case ETY_VAR: { @@ -1130,7 +1047,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan *dest = kh_val(const_map, it); return 1; } - if (fatal) printf("Error: failed to evaluate expression: expression is not constant (variable)\n"); + if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (variable)\n"); return 0; } case ETY_CONST: @@ -1140,18 +1057,16 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan // case ETY_GENERIC: case ETY_CALL: - if (fatal) printf("Error: failed to evaluate expression: expression is not constant (function call)\n"); + if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (function call)\n"); return 0; case ETY_ACCESS: case ETY_PTRACCESS: - if (fatal) printf("Error: failed to evaluate expression: expression is not constant (member access)\n"); + if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (member access)\n"); return 0; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" case ETY_UNARY: - if (!eval_expression(e->val.unary.e, const_map, dest, fatal)) return 0; + if (!eval_expression(li, target, e->val.unary.e, const_map, dest, fatal)) return 0; switch (e->val.unary.typ) { case UOT_POSTINCR: @@ -1160,7 +1075,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case UOT_PREDECR: case UOT_REF: case UOT_DEREF: - if (fatal) printf("Error: failed to evaluate expression: expression is not constant (assignment or memory accesses)\n"); + if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (assignment or memory accesses)\n"); return 0; case UOT_POS: return 1; // Nothing to do @@ -1180,7 +1095,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case NCT_FLOAT: case NCT_DOUBLE: case NCT_LDOUBLE: - if (fatal) printf("Error: failed to evaluate expression: cannot bitwise-negate a floating point number\n"); + if (fatal) log_error(li, "failed to evaluate expression: cannot bitwise-negate a floating point number\n"); return 0; case NCT_INT32: dest->val.i32 = ~dest->val.i32; return 1; case NCT_UINT32: dest->val.u32 = ~dest->val.u32; return 1; @@ -1190,9 +1105,12 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan } case UOT_BNOT: switch (dest->typ) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" case NCT_FLOAT: dest->typ = NCT_INT32; dest->val.i32 = !dest->val.f; return 1; case NCT_DOUBLE: dest->typ = NCT_INT32; dest->val.i32 = !dest->val.d; return 1; case NCT_LDOUBLE: dest->typ = NCT_INT32; dest->val.i32 = !dest->val.l; return 1; +#pragma GCC diagnostic pop case NCT_INT32: dest->typ = NCT_INT32; dest->val.i32 = !dest->val.i32; return 1; case NCT_UINT32: dest->typ = NCT_INT32; dest->val.i32 = !dest->val.u32; return 1; case NCT_INT64: dest->typ = NCT_INT32; dest->val.i32 = !dest->val.i64; return 1; @@ -1204,8 +1122,8 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case ETY_BINARY: { num_constant_t dest1, dest2; - if (!eval_expression(e->val.binary.e1, const_map, &dest1, fatal)) return 0; - if (!eval_expression(e->val.binary.e2, const_map, &dest2, fatal)) return 0; + if (!eval_expression(li, target, e->val.binary.e1, const_map, &dest1, fatal)) return 0; + if (!eval_expression(li, target, e->val.binary.e2, const_map, &dest2, fatal)) return 0; switch (e->val.binary.typ) { case BOT_ASSGN_EQ: @@ -1220,7 +1138,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case BOT_ASSGN_AXOR: case BOT_ASSGN_AOR: case BOT_ARRAY: // Is this possible? - if (fatal) printf("Error: failed to evaluate expression: expression is not constant (assignments)\n"); + if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (assignments)\n"); return 0; #define DOIT(op) \ promote_csts(&dest1, &dest2); \ @@ -1240,7 +1158,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case NCT_FLOAT: \ case NCT_DOUBLE: \ case NCT_LDOUBLE: \ - if (fatal) printf("Error: failed to evaluate expression: binary operation %u incompatible with floating point numbers\n", e->val.binary.typ); \ + if (fatal) log_error(li, "failed to evaluate expression: binary operation %u incompatible with floating point numbers\n", e->val.binary.typ); \ return 0; \ case NCT_INT32: dest->val.i32 = dest1.val.i32 op dest2.val.i32; return 1; \ case NCT_UINT32: dest->val.u32 = dest1.val.u32 op dest2.val.u32; return 1; \ @@ -1251,14 +1169,14 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan #define DOIT_BOOL(op) \ promote_csts(&dest1, &dest2); \ switch (dest1.typ) { \ - case NCT_FLOAT: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.f op dest2.val.f ; return 1; \ - case NCT_DOUBLE: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.d op dest2.val.d ; return 1; \ - case NCT_LDOUBLE: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.l op dest2.val.l ; return 1; \ - case NCT_INT32: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.i32 op dest2.val.i32; return 1; \ - case NCT_UINT32: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.u32 op dest2.val.u32; return 1; \ - case NCT_INT64: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.i64 op dest2.val.i64; return 1; \ - case NCT_UINT64: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.u64 op dest2.val.u64; return 1; \ - default: return 0; \ + case NCT_FLOAT: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.f op dest2.val.f ; return 1; \ + case NCT_DOUBLE: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.d op dest2.val.d ; return 1; \ + case NCT_LDOUBLE: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.l op dest2.val.l ; return 1; \ + case NCT_INT32: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.i32 op dest2.val.i32; return 1; \ + case NCT_UINT32: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.u32 op dest2.val.u32; return 1; \ + case NCT_INT64: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.i64 op dest2.val.i64; return 1; \ + case NCT_UINT64: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.u64 op dest2.val.u64; return 1; \ + default: return 0; \ } case BOT_ADD: DOIT(+) case BOT_SUB: DOIT(-) @@ -1271,13 +1189,19 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case BOT_GT: DOIT_BOOL(>) case BOT_LE: DOIT_BOOL(<=) case BOT_GE: DOIT_BOOL(>=) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" case BOT_EQ: DOIT_BOOL(==) case BOT_NE: DOIT_BOOL(!=) +#pragma GCC diagnostic pop case BOT_AAND: DOIT_INT(&) case BOT_AXOR: DOIT_INT(^) case BOT_AOR: DOIT_INT(|) - case BOT_BAND: DOIT(&&) - case BOT_BOR: DOIT(||) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + case BOT_BAND: DOIT_BOOL(&&) + case BOT_BOR: DOIT_BOOL(||) +#pragma GCC diagnostic pop case BOT_COMMA: *dest = dest2; return 1; #undef DOIT_BOOL #undef DOIT_INT @@ -1287,17 +1211,20 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case ETY_TERNARY: { num_constant_t dest1, dest2, dest3; - if (!eval_expression(e->val.ternary.e1, const_map, &dest1, fatal)) return 0; - if (!eval_expression(e->val.ternary.e2, const_map, &dest2, fatal)) return 0; - if (!eval_expression(e->val.ternary.e3, const_map, &dest3, fatal)) return 0; + if (!eval_expression(li, target, e->val.ternary.e1, const_map, &dest1, fatal)) return 0; + if (!eval_expression(li, target, e->val.ternary.e2, const_map, &dest2, fatal)) return 0; + if (!eval_expression(li, target, e->val.ternary.e3, const_map, &dest3, fatal)) return 0; switch (e->val.ternary.typ) { case TOT_COND: promote_csts(&dest2, &dest3); switch (dest1.typ) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" case NCT_FLOAT: *dest = dest1.val.f ? dest2 : dest3; return 1; case NCT_DOUBLE: *dest = dest1.val.d ? dest2 : dest3; return 1; case NCT_LDOUBLE: *dest = dest1.val.l ? dest2 : dest3; return 1; +#pragma GCC diagnostic pop case NCT_INT32: *dest = dest1.val.i32 ? dest2 : dest3; return 1; case NCT_UINT32: *dest = dest1.val.u32 ? dest2 : dest3; return 1; case NCT_INT64: *dest = dest1.val.i64 ? dest2 : dest3; return 1; @@ -1306,17 +1233,49 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan } default: return 0; } } -#pragma GCC diagnostic pop // case ETY_INIT_LIST: case ETY_CAST: - if (!eval_expression(e->val.cast.e, const_map, dest, fatal)) return 0; + if (!eval_expression(li, target, e->val.cast.e, const_map, dest, fatal)) return 0; if (e->val.cast.typ->typ == TYPE_BUILTIN) { switch (e->val.cast.typ->val.builtin) { + case BTT_VOID: + if (fatal) log_error(li, "invalid cast to void\n"); + return 0; + case BTT_BOOL: + switch (dest->typ) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + case NCT_FLOAT: dest->val.u32 = (_Bool)dest->val.f; break; + case NCT_DOUBLE: dest->val.u32 = (_Bool)dest->val.d; break; + case NCT_LDOUBLE: dest->val.u32 = (_Bool)dest->val.l; break; +#pragma GCC diagnostic pop + case NCT_INT32: dest->val.u32 = (_Bool)dest->val.i32; break; + case NCT_UINT32: dest->val.u32 = (_Bool)dest->val.u32; break; + case NCT_INT64: dest->val.u32 = (_Bool)dest->val.i64; break; + case NCT_UINT64: dest->val.u32 = (_Bool)dest->val.u64; break; + } + dest->typ = NCT_UINT32; + return 1; + case BTT_SCHAR: + case BTT_S8: + cast_s8: + switch (dest->typ) { + case NCT_FLOAT: dest->val.i32 = (int8_t)dest->val.f; break; + case NCT_DOUBLE: dest->val.i32 = (int8_t)dest->val.d; break; + case NCT_LDOUBLE: dest->val.i32 = (int8_t)dest->val.l; break; + case NCT_INT32: dest->val.i32 = (int8_t)dest->val.i32; break; + case NCT_UINT32: dest->val.i32 = (int8_t)dest->val.u32; break; + case NCT_INT64: dest->val.i32 = (int8_t)dest->val.i64; break; + case NCT_UINT64: dest->val.i32 = (int8_t)dest->val.u64; break; + } + dest->typ = NCT_INT32; + return 1; case BTT_UCHAR: case BTT_U8: + cast_u8: switch (dest->typ) { case NCT_FLOAT: dest->val.u32 = (uint8_t)dest->val.f; break; case NCT_DOUBLE: dest->val.u32 = (uint8_t)dest->val.d; break; @@ -1328,9 +1287,37 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan } dest->typ = NCT_UINT32; return 1; + case BTT_SHORT: + case BTT_SSHORT: + case BTT_S16: + switch (dest->typ) { + case NCT_FLOAT: dest->val.i32 = (int16_t)dest->val.f; break; + case NCT_DOUBLE: dest->val.i32 = (int16_t)dest->val.d; break; + case NCT_LDOUBLE: dest->val.i32 = (int16_t)dest->val.l; break; + case NCT_INT32: dest->val.i32 = (int16_t)dest->val.i32; break; + case NCT_UINT32: dest->val.i32 = (int16_t)dest->val.u32; break; + case NCT_INT64: dest->val.i32 = (int16_t)dest->val.i64; break; + case NCT_UINT64: dest->val.i32 = (int16_t)dest->val.u64; break; + } + dest->typ = NCT_INT32; + return 1; + case BTT_USHORT: + case BTT_U16: + switch (dest->typ) { + case NCT_FLOAT: dest->val.u32 = (uint16_t)dest->val.f; break; + case NCT_DOUBLE: dest->val.u32 = (uint16_t)dest->val.d; break; + case NCT_LDOUBLE: dest->val.u32 = (uint16_t)dest->val.l; break; + case NCT_INT32: dest->val.u32 = (uint16_t)dest->val.i32; break; + case NCT_UINT32: dest->val.u32 = (uint16_t)dest->val.u32; break; + case NCT_INT64: dest->val.u32 = (uint16_t)dest->val.i64; break; + case NCT_UINT64: dest->val.u32 = (uint16_t)dest->val.u64; break; + } + dest->typ = NCT_UINT32; + return 1; case BTT_INT: case BTT_SINT: case BTT_S32: + cast_s32: switch (dest->typ) { case NCT_FLOAT: dest->val.i32 = (int32_t)dest->val.f; break; case NCT_DOUBLE: dest->val.i32 = (int32_t)dest->val.d; break; @@ -1344,6 +1331,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan return 1; case BTT_UINT: case BTT_U32: + cast_u32: switch (dest->typ) { case NCT_FLOAT: dest->val.u32 = (uint32_t)dest->val.f; break; case NCT_DOUBLE: dest->val.u32 = (uint32_t)dest->val.d; break; @@ -1355,10 +1343,24 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan } dest->typ = NCT_UINT32; return 1; - case BTT_ULONG: - // Warning: assuming sizeof(long) == 8 on the current target - // TODO: use machine to select between U32 and U64 + case BTT_LONGLONG: + case BTT_SLONGLONG: + case BTT_S64: + cast_s64: + switch (dest->typ) { + case NCT_FLOAT: dest->val.i64 = (int64_t)dest->val.f; break; + case NCT_DOUBLE: dest->val.i64 = (int64_t)dest->val.d; break; + case NCT_LDOUBLE: dest->val.i64 = (int64_t)dest->val.l; break; + case NCT_INT32: dest->val.i64 = (int64_t)dest->val.i32; break; + case NCT_UINT32: dest->val.i64 = (int64_t)dest->val.u32; break; + case NCT_INT64: break; + case NCT_UINT64: dest->val.i64 = (int64_t)dest->val.u64; break; + } + dest->typ = NCT_INT64; + return 1; + case BTT_ULONGLONG: case BTT_U64: + cast_u64: switch (dest->typ) { case NCT_FLOAT: dest->val.u64 = (uint64_t)dest->val.f; break; case NCT_DOUBLE: dest->val.u64 = (uint64_t)dest->val.d; break; @@ -1370,25 +1372,31 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan } dest->typ = NCT_UINT64; return 1; - case BTT_VOID: - case BTT_BOOL: - case BTT_CHAR: // May be signed or unsigned depending on the machine - case BTT_SCHAR: - case BTT_SHORT: - case BTT_SSHORT: - case BTT_USHORT: + case BTT_CHAR: + if (target->unsigned_char) goto cast_u8; + else goto cast_s8; case BTT_LONG: case BTT_SLONG: - case BTT_LONGLONG: - case BTT_SLONGLONG: - case BTT_ULONGLONG: + if (target->size_long == 4) { + goto cast_s32; + } else if (target->size_long == 8) { + goto cast_s64; + } else { + log_internal(li, "unsupported cast to long with target sizeof(long) == %zu\n", target->size_long); + return 0; + } + case BTT_ULONG: + if (target->size_long == 4) { + goto cast_u32; + } else if (target->size_long == 8) { + goto cast_u64; + } else { + log_internal(li, "unsupported cast to unsigned long with target sizeof(long) == %zu\n", target->size_long); + return 0; + } case BTT_INT128: case BTT_SINT128: case BTT_UINT128: - case BTT_S8: - case BTT_S16: - case BTT_U16: - case BTT_S64: case BTT_FLOAT: case BTT_CFLOAT: case BTT_IFLOAT: @@ -1403,11 +1411,11 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan case BTT_IFLOAT128: case BTT_VA_LIST: default: - if (fatal) printf("Error: TODO: cast to builtin %s in constant expression\n", builtin2str[e->val.cast.typ->val.builtin]); + if (fatal) log_TODO(li, "unsupported cast to builtin %s in constant expression\n", builtin2str[e->val.cast.typ->val.builtin]); return 0; } } else { - if (fatal) printf("Error: cast in constant expression\n"); + if (fatal) log_TODO(li, "unsupported cast in constant expression\n"); return 0; } @@ -1426,7 +1434,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s // Empty destructor *tok = proc_next_token(prep); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) { - printf("Error: unexpected token in static assertion declaration\n"); + log_error(&tok->loginfo, "unexpected token in static assertion declaration\n"); proc_token_del(tok); goto failed; } @@ -1437,13 +1445,13 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s goto failed; } if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_COMMA)) { - printf("Error: unexpected token in static assertion expression\n"); + log_error(&tok->loginfo, "unexpected token in static assertion expression\n"); expr_del(e); proc_token_del(tok); goto failed; } num_constant_t eval; - if (!eval_expression(e, const_map, &eval, 1)) { + if (!eval_expression(&tok->loginfo, target, e, const_map, &eval, 1)) { expr_del(e); // Empty destructor goto failed; @@ -1451,37 +1459,40 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s expr_del(e); *tok = proc_next_token(prep); if ((tok->tokt != PTOK_STRING) || !tok->tokv.sisstr) { - printf("Error: unexpected token in static assertion message\n"); + log_error(&tok->loginfo, "unexpected token in static assertion message\n"); proc_token_del(tok); goto failed; } string_t *errmsg = tok->tokv.str; *tok = proc_next_token(prep); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) { - printf("Error: unexpected token in static assertion message\n"); + log_error(&tok->loginfo, "unexpected token in static assertion message\n"); proc_token_del(tok); goto failed; } *tok = proc_next_token(prep); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_SEMICOLON)) { - printf("Error: unexpected token after static assertion\n"); + log_error(&tok->loginfo, "unexpected token after static assertion\n"); proc_token_del(tok); goto failed; } int iserror; switch (eval.typ) { - case NCT_FLOAT: iserror = (int)eval.val.f == 0; break; - case NCT_DOUBLE: iserror = (int)eval.val.d == 0; break; - case NCT_LDOUBLE: iserror = (int)eval.val.l == 0; break; - case NCT_INT32: iserror = eval.val.i32 == 0; break; - case NCT_UINT32: iserror = eval.val.u32 == 0; break; - case NCT_INT64: iserror = eval.val.i64 == 0; break; - case NCT_UINT64: iserror = eval.val.u64 == 0; break; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + case NCT_FLOAT: iserror = !eval.val.f; break; + case NCT_DOUBLE: iserror = !eval.val.d; break; + case NCT_LDOUBLE: iserror = !eval.val.l; break; +#pragma GCC diagnostic pop + case NCT_INT32: iserror = !eval.val.i32; break; + case NCT_UINT32: iserror = !eval.val.u32; break; + case NCT_INT64: iserror = !eval.val.i64; break; + case NCT_UINT64: iserror = !eval.val.u64; break; default: iserror = 1; } if (iserror) { - printf("Error: static assertion failed: %s\n", string_content(errmsg)); + log_error(&tok->loginfo, "static assertion failed: %s\n", string_content(errmsg)); string_del(errmsg); // Empty destructor goto failed; @@ -1493,15 +1504,14 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s parse_cur_token_decl: if (tok->tokt == PTOK_EOF) { - printf("Error: unexpected end of file in declaration\n"); - proc_token_print(tok); + log_error(&tok->loginfo, "unexpected end of file in declaration\n"); goto failed; } // Storage if (storage && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_AUTO)) { if (*storage == TMPSTO_NONE) *storage = TMPSTO_AUTO; else { - printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1510,7 +1520,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s if (*storage == TMPSTO_NONE) *storage = TMPSTO_EXTERN; else if (*storage == TMPSTO_TLS) *storage = TMPSTO_TLS_EXTERN; else { - printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1518,7 +1528,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if (storage && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_REGISTER)) { if (*storage == TMPSTO_NONE) *storage = TMPSTO_REG; else { - printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1527,7 +1537,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s if (*storage == TMPSTO_NONE) *storage = TMPSTO_STATIC; else if (*storage == TMPSTO_TLS) *storage = TMPSTO_TLS_STATIC; else { - printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1537,7 +1547,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s else if (*storage == TMPSTO_EXTERN) *storage = TMPSTO_TLS_EXTERN; else if (*storage == TMPSTO_STATIC) *storage = TMPSTO_TLS_STATIC; else { - printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1545,7 +1555,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if (storage && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_TYPEDEF)) { if (*storage == TMPSTO_NONE) *storage = TMPSTO_TYPEDEF; else { - printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1568,9 +1578,30 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s // Empty destructor *tok = proc_next_token(prep); if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { - printf("Error: TODO: _Atomic(type-name)\n"); + if (*spec != SPEC_NONE) { + log_error(&tok->loginfo, "unexpected symbol '('\n"); + // Empty destructor + goto failed; + } + *spec = SPEC_TYPE; + if (!parse_type_name(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, SYM_RPAREN, &typ)) { + goto failed; + } + if (!typ->is_validated) { + log_internal(&tok->loginfo, "_Atomic() type is not validated\n"); + type_del(typ); + // Empty destructor + goto failed; + } + if ((typ->typ == TYPE_ARRAY) || (typ->typ == TYPE_FUNCTION) || typ->is_atomic || typ->is_const || typ->is_restrict || typ->is_volatile) { + log_error(&tok->loginfo, "the type name in an _Atomic() may not be an array, a function, atomic, or qualified\n"); + type_del(typ); + // Empty destructor + goto failed; + } // Empty destructor - goto failed; + *tok = proc_next_token(prep); + goto parse_cur_token_decl; } else { typ->is_atomic = 1; goto parse_cur_token_decl; @@ -1591,16 +1622,16 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s // Specifier #define SPEC(bt,post) \ - if (*spec == SPEC_NONE) { \ - *spec = SPEC_BUILTIN; \ - typ->typ = TYPE_BUILTIN; \ - typ->val.builtin = BTT_ ## bt; \ - post \ - } else { \ - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); \ - goto failed; \ - } \ - *tok = proc_next_token(prep); \ + if (*spec == SPEC_NONE) { \ + *spec = SPEC_BUILTIN; \ + typ->typ = TYPE_BUILTIN; \ + typ->val.builtin = BTT_ ## bt; \ + post \ + } else { \ + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); \ + goto failed; \ + } \ + *tok = proc_next_token(prep); \ goto parse_cur_token_decl; #define SPEC_SIGNED(bt, allow_int) \ if ((*spec == SPEC_NONE) || (allow_int && (*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_INT))) { \ @@ -1614,7 +1645,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s *spec = allow_int ? *spec : SPEC_BUILTIN; \ typ->val.builtin = BTT_U ## bt; \ } else { \ - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); \ + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); \ goto failed; \ } \ *tok = proc_next_token(prep); \ @@ -1635,7 +1666,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_LONGDOUBLE)) { typ->val.builtin = BTT_CLONGDOUBLE; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1654,7 +1685,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_LONGDOUBLE)) { typ->val.builtin = BTT_ILONGDOUBLE; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1684,7 +1715,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s *spec = SPEC_BUILTIN; typ->val.builtin = BTT_LONGDOUBLE; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1703,7 +1734,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s typ->typ = TYPE_BUILTIN; typ->val.builtin = BTT_IFLOAT; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1722,7 +1753,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s typ->typ = TYPE_BUILTIN; typ->val.builtin = BTT_IFLOAT128; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1737,7 +1768,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if (*spec == SPEC_BUILTIN_NOINT) { *spec = SPEC_BUILTIN; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1770,7 +1801,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if (*spec == SPEC_IMAGINARY) { *spec = SPEC_LONGIMAGINARY; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1793,7 +1824,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if (((*spec == SPEC_BUILTIN_NOINT) || (*spec == SPEC_BUILTIN)) && (typ->val.builtin == BTT_SHORT)) { typ->val.builtin = BTT_SSHORT; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1814,7 +1845,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } else if (((*spec == SPEC_BUILTIN_NOINT) || (*spec == SPEC_BUILTIN)) && (typ->val.builtin == BTT_SHORT)) { typ->val.builtin = BTT_USHORT; } else { - printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); + log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); goto failed; } *tok = proc_next_token(prep); @@ -1828,19 +1859,13 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s // The ident is the type-specifier khiter_t it = kh_get(type_map, type_map, string_content(tok->tokv.str)); if (it == kh_end(type_map)) { - printf("Error: invalid type '%s' (ident is not a typedef)\n" - "Current state:\n" - " storage: %p/%u\n" - " spec: %u\n" - " type: ", string_content(tok->tokv.str), storage, storage ? *storage : TMPSTO_NONE, *spec); - type_print(typ); - printf("\n"); + log_error(&tok->loginfo, "invalid type '%s' (ident is not a typedef)\n", string_content(tok->tokv.str)); string_del(tok->tokv.str); goto failed; } else { *spec = SPEC_TYPE; if (!type_copy_into(typ, kh_val(type_map, it))) { - printf("Failed to duplicate type infos\n"); + log_memory("failed to duplicate type infos\n"); string_del(tok->tokv.str); goto failed; } @@ -1855,32 +1880,34 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s // Empty destructor *tok = proc_next_token(prep); - khiter_t it = kh_end(struct_map); // Iterator into the struct_map + string_t *tag; if (tok->tokt == PTOK_IDENT) { - string_t *tag = tok->tokv.str; + tag = tok->tokv.str; // Token moved *tok = proc_next_token(prep); + khiter_t it; // Iterator into the struct_map int iret; it = kh_put(struct_map, struct_map, string_content(tag), &iret); if (iret < 0) { - printf("Error: failed to add structure to struct map\n"); + log_memory("failed to add structure to struct map\n"); proc_token_del(tok); goto failed; } else if (iret == 0) { // Structure already declared or defined if (kh_val(struct_map, it)->is_struct != is_struct) { - printf("Error: incoherent struct/union tagging of %s\n", string_content(tag)); + log_error(&tok->loginfo, "incoherent struct/union tagging of %s\n", string_content(tag)); string_del(tag); proc_token_del(tok); goto failed; } ++kh_val(struct_map, it)->nrefs; string_del(tag); + tag = kh_val(struct_map, it)->tag; } else { kh_val(struct_map, it) = struct_new(is_struct, tag); if (!kh_val(struct_map, it)) { - printf("Error: failed to create new structure metadata structure\n"); + log_memory("failed to create new structure metadata structure\n"); string_del(tag); proc_token_del(tok); goto failed; @@ -1890,10 +1917,11 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s typ->val.st = kh_val(struct_map, it); typ->is_incomplete = !typ->val.st->is_defined; } else { + tag = NULL; typ->typ = TYPE_STRUCT_UNION; typ->val.st = struct_new(is_struct, NULL); if (!typ->val.st) { - printf("Error: failed to create new structure metadata structure\n"); + log_memory("failed to create new structure metadata structure\n"); proc_token_del(tok); goto failed; } @@ -1901,24 +1929,18 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_LBRACKET)) { if (typ->val.st->is_defined) { - printf("Error: TODO: struct redefinition\n" - "Current state:\n" - " storage: %p/%u\n" - " spec: %u\n" - " type: ", storage, storage ? *storage : TMPSTO_NONE, *spec); - type_print(typ); - printf("\n"); + log_TODO(&tok->loginfo, "struct redefinition (tag is %s)\n", typ->val.st->tag ? string_content(typ->val.st->tag) : ""); goto failed; } VECTOR(st_members) *members = vector_new(st_members); if (!members) { - printf("Failed to create a members vector\n"); + log_memory("failed to create a members vector\n"); goto failed; } type_t *typ2 = type_new(); if (!typ2) { - printf("Failed to create a type info structure\n"); + log_memory("failed to create a type info structure\n"); vector_del(st_members, members); goto failed; } @@ -1941,13 +1963,13 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s // A struct-declaration that does not declare an anonymous structure or anonymous union // shall contain a struct-declarator-list. if ((typ2->typ != TYPE_STRUCT_UNION) || typ2->val.st->tag) { - printf("Error: missing struct-declarator-list\n"); + log_error(&tok->loginfo, "missing struct-declarator-list\n"); vector_del(st_members, members); type_del(typ2); goto failed; } if (!vector_push(st_members, members, ((st_member_t){.name = NULL, .typ = typ2, .is_bitfield = 0}))) { - printf("Error: failed to add anonymous structure member\n"); + log_memory("failed to add anonymous structure member\n"); vector_del(st_members, members); type_del(typ2); // Empty destructor @@ -1955,7 +1977,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } typ2 = type_new(); if (!typ2) { - printf("Failed to create a type info structure\n"); + log_memory("failed to create a type info structure\n"); vector_del(st_members, members); // Empty destructor goto failed; @@ -1974,7 +1996,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s dest2.structms.const_map = const_map; dest2.structms.dest = members; if (!parse_declarator(target, &dest2, prep, tok, TMPSTO_NONE, FSPEC_NONE, typ2, 0, 1, 1, 1)) { - printf("Error parsing struct-declarator-list\n"); + log_error(&tok->loginfo, "error parsing struct-declarator-list\n"); vector_del(st_members, members); type_del(typ2); // Token is deleted @@ -1982,14 +2004,14 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } type_del(typ2); if ((tok->tokt != PTOK_SYM) && (tok->tokv.sym != SYM_SEMICOLON)) { - printf("Error parsing struct-declarator-list (invalid next token)\n"); + log_error(&tok->loginfo, "error parsing struct-declarator-list (invalid next token)\n"); vector_del(st_members, members); proc_token_del(tok); goto failed; } typ2 = type_new(); if (!typ2) { - printf("Failed to create a type info structure\n"); + log_memory("failed to create a type info structure\n"); vector_del(st_members, members); // Empty destructor goto failed; @@ -1998,7 +2020,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } type_del(typ2); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RBRACKET)) { - printf("Error parsing struct-declarator-list (invalid next token)\n"); + log_error(&tok->loginfo, "error parsing struct-declarator-list (invalid next token)\n"); vector_del(st_members, members); proc_token_del(tok); goto failed; @@ -2006,6 +2028,13 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s typ->is_incomplete = 0; typ->is_validated = 0; + if (tag) { + khiter_t it = kh_get(type_set, type_set, typ); + if (it != kh_end(type_set)) { + kh_key(type_set, it)->is_incomplete = 0; + kh_key(type_set, it)->is_validated = 0; + } + } typ->val.st->has_incomplete = 0; // Filled by the validate_type step typ->val.st->nmembers = vector_size(st_members, members); typ->val.st->members = vector_steal(st_members, members); @@ -2013,8 +2042,8 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s *tok = proc_next_token(prep); goto parse_cur_token_decl; } else { - if (it == kh_end(struct_map)) { - printf("Error: invalid structure declaration: missing tag and/or definition\n"); + if (!tag) { + log_error(&tok->loginfo, "invalid structure declaration: missing tag and/or definition\n"); proc_token_del(tok); goto failed; } @@ -2033,19 +2062,19 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s } if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LBRACKET)) { if (!tag) { - printf("Error: unexpected token after keyword 'enum'\n"); + log_error(&tok->loginfo, "unexpected token after keyword 'enum'\n"); proc_token_del(tok); goto failed; } khiter_t it = kh_get(type_map, enum_map, string_content(tag)); if (it == kh_end(enum_map)) { - printf("Error: enumeration %s has not been defined yet\n", string_content(tag)); // TODO? + log_error(&tok->loginfo, "enumeration %s has not been defined yet\n", string_content(tag)); // TODO? string_del(tag); proc_token_del(tok); goto failed; } if (!type_copy_into(typ, kh_val(enum_map, it))) { - printf("Failed to duplicate enum type infos\n"); + log_memory("failed to duplicate enum type infos\n"); string_del(tag); proc_token_del(tok); goto failed; @@ -2068,25 +2097,93 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s num_constant_t cst = { .typ = NCT_INT32, .val.i32 = -1 }; // Empty destructor *tok = proc_next_token(prep); + if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_RBRACKET)) { + log_error(&tok->loginfo, "expected enum constant name before '}'\n"); + proc_token_del(tok); + goto failed; + } int iret; while ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RBRACKET)) { if (tok->tokt != PTOK_IDENT) { - printf("Error: invalid token in enumeration definition\n"); + log_error(&tok->loginfo, "unexpected token in enumeration definition\n"); if (tag) string_del(tag); proc_token_del(tok); goto failed; } char *ident = string_steal(tok->tokv.str); *tok = proc_next_token(prep); + while ((tok->tokt == PTOK_IDENT) && !strcmp(string_content(tok->tokv.str), "__attribute__")) { + // Attribute + string_del(tok->tokv.str); + *tok = proc_next_token(prep); + if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) { + log_error(&tok->loginfo, "unexpected token, expected '('\n"); + free(ident); + if (tag) string_del(tag); + proc_token_del(tok); + goto failed; + } + // Empty destructor + *tok = proc_next_token(prep); + if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) { + log_error(&tok->loginfo, "unexpected token, expected '('\n"); + free(ident); + if (tag) string_del(tag); + // Empty destructor + goto failed; + } + // Empty destructor + *tok = proc_next_token(prep); + enum_attribute_list: + if ((tok->tokt == PTOK_IDENT) && TOKEN_MATCH_ATTR(deprecated)) { + log_warning(&tok->loginfo, "ignoring enum constant attribute 'deprecated'\n"); + string_del(tok->tokv.str); + *tok = proc_next_token(prep); + if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_COMMA)) { + // Empty destructor + *tok = proc_next_token(prep); + goto enum_attribute_list; + } else goto enum_attribute_list_end; + } + if ((tok->tokt == PTOK_IDENT) && TOKEN_MATCH_ATTR(unavailable)) { + log_warning(&tok->loginfo, "ignoring enum constant attribute 'unavailable'\n"); + string_del(tok->tokv.str); + *tok = proc_next_token(prep); + if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_COMMA)) { + // Empty destructor + *tok = proc_next_token(prep); + goto enum_attribute_list; + } else goto enum_attribute_list_end; + } + enum_attribute_list_end: + if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) { + log_error(&tok->loginfo, "unexpected token, expected ident or ')'\n"); + free(ident); + if (tag) string_del(tag); + // Empty destructor + goto failed; + } + // Empty destructor + *tok = proc_next_token(prep); + if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) { + log_error(&tok->loginfo, "unexpected token, expected ')'\n"); + free(ident); + if (tag) string_del(tag); + // Empty destructor + goto failed; + } + // Empty destructor + *tok = proc_next_token(prep); + } khiter_t it = kh_put(const_map, const_map, ident, &iret); if (iret < 0) { - printf("Error: failed to add constant %s to the constants map\n", ident); + log_memory("failed to add constant %s to the constants map\n", ident); free(ident); if (tag) string_del(tag); proc_token_del(tok); goto failed; } else if (iret == 0) { - printf("Error: constant %s is already in the constants map\n", ident); + log_error(&tok->loginfo, "constant %s is already defined\n", ident); free(ident); if (tag) string_del(tag); proc_token_del(tok); @@ -2114,7 +2211,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s break; case NCT_UINT64: if (cst.val.u64 == UINT64_MAX) { - printf("Error: enum constant is too big\n"); + log_error(&tok->loginfo, "enum constant is too big\n"); if (tag) string_del(tag); proc_token_del(tok); goto failed; @@ -2124,7 +2221,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s case NCT_DOUBLE: case NCT_LDOUBLE: default: - printf("Internal error: enum constant is a float/double/ldouble\n"); + log_internal(&tok->loginfo, "enum constant is a float/double/ldouble\n"); if (tag) string_del(tag); proc_token_del(tok); goto failed; @@ -2137,13 +2234,13 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s goto failed; } if ((tok->tokt != PTOK_SYM) || ((tok->tokv.sym != SYM_COMMA) && (tok->tokv.sym != SYM_RBRACKET))) { - printf("Error: unexpected token during enumeration declaration\n"); + log_error(&tok->loginfo, "unexpected token during enumeration declaration\n"); expr_del(e); if (tag) string_del(tag); proc_token_del(tok); goto failed; } - if (!eval_expression(e, const_map, &cst, 1)) { + if (!eval_expression(&tok->loginfo, target, e, const_map, &cst, 1)) { expr_del(e); if (tag) string_del(tag); // Empty destructor @@ -2156,7 +2253,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s if (cst.val.i32 < 0) { has_neg = 1; if (btt == BTT_U64) { - printf("Error: enum constant is too big\n"); + log_error(&tok->loginfo, "enum constant is too big\n"); if (tag) string_del(tag); // Empty destructor goto failed; @@ -2177,7 +2274,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s not_in_i32 = 1; } if (btt == BTT_U64) { - printf("Error: enum constant is too big\n"); + log_error(&tok->loginfo, "enum constant is too big\n"); if (tag) string_del(tag); // Empty destructor goto failed; @@ -2198,7 +2295,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s if (cst.val.u64 > (uint32_t)INT32_MAX) { not_in_i32 = 1; if (has_neg && (cst.val.u64 > (uint64_t)INT64_MAX)) { - printf("Error: enum constant is too big\n"); + log_error(&tok->loginfo, "enum constant is too big\n"); if (tag) string_del(tag); // Empty destructor goto failed; @@ -2210,7 +2307,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s case NCT_DOUBLE: case NCT_LDOUBLE: default: - printf("Error: invalid floating-point enumeration constant\n"); + log_error(&tok->loginfo, "invalid floating-point enumeration constant\n"); if (tag) string_del(tag); // Empty destructor goto failed; @@ -2224,19 +2321,19 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s char *ctag = string_steal(tag); khiter_t it = kh_put(type_map, enum_map, ctag, &iret); if (iret < 0) { - printf("Error: failed to add enumeration %s to the type map\n", ctag); + log_memory("failed to add enumeration %s to the type map\n", ctag); free(ctag); // Empty destructor goto failed; } else if (iret == 0) { - printf("Error: enumeration %s already exists\n", ctag); + log_error(&tok->loginfo, "enumeration %s already exists\n", ctag); free(ctag); // Empty destructor goto failed; } type_t *new_typ = type_new(); if (!new_typ) { - printf("Error: failed to create type info for enumeration %s\n", ctag); + log_memory("failed to create type info for enumeration %s\n", ctag); free(ctag); kh_del(type_map, enum_map, it); // Empty destructor @@ -2247,7 +2344,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s typ->val.typ = new_typ->val.typ = (*builtins)[btt]; typ->val.typ->nrefs += 2; new_typ = type_try_merge(new_typ, type_set); - validate_type(target, new_typ); // Assume it returns 1 + validate_type(&tok->loginfo, target, new_typ); // Assume it returns 1 kh_val(enum_map, it) = new_typ; } else { typ->typ = TYPE_ENUM; @@ -2269,14 +2366,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s return 1; invalid_token: - printf("Error: unexpected token (parse_declaration_specifier)\n" - "Current state:\n" - " storage: %p/%u\n" - " spec: %u\n" - " type: ", storage, storage ? *storage : TMPSTO_NONE, *spec); - type_print(typ); - printf("\n"); - proc_token_print(tok); + log_error(&tok->loginfo, "unexpected token (parse_declaration_specifier)\n"); proc_token_del(tok); failed: @@ -2294,7 +2384,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d type_t *cur_bottom = NULL; VECTOR(size_t) *nptr_stack = vector_new_cap(size_t, 1); if (!nptr_stack) { - printf("Failed to parse init_declarator_list (allocate nptr_stack)\n"); + log_memory("failed to allocate nptr stack\n"); proc_token_del(tok); goto failed0; } @@ -2302,31 +2392,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d while (1) { switch (tok->tokt) { case PTOK_IDENT: - if (!has_ident) { - if (allow_decl) { - cur_ident = tok->tokv.str; - has_ident = 1; - *tok = proc_next_token(prep); - break; - } else { - printf("Error: unexpected identifier: abstract declarator do not contain a name\n" - "Current state:\n" - " storage: %u\n" - " type: ", storage); - type_print(typ); - printf("\n"); - proc_token_print(tok); - proc_token_del(tok); - goto failed; - } + if (!has_ident && allow_decl) { + cur_ident = tok->tokv.str; + has_ident = 1; + *tok = proc_next_token(prep); + break; } else { - printf("Error: unexpected identifier\n" - "Current state:\n" - " storage: %u\n" - " type: ", storage); - type_print(typ); - printf("\n"); - proc_token_print(tok); + log_error(&tok->loginfo, "unexpected identifier\n"); proc_token_del(tok); goto failed; } @@ -2337,7 +2409,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d VECTOR(types) *args = vector_new(types); if (!args) { - printf("Error: failed to create new type (function argument)\n"); + log_memory("failed to create new type (function argument)\n"); // Empty destructor goto failed; } @@ -2350,7 +2422,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d vector_del(types, args); new_typ = type_new(); if (!new_typ) { - printf("Error: failed to create new function type\n"); + log_memory("failed to create new function type\n"); // Empty destructor goto failed; } @@ -2362,7 +2434,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d goto end_fun; } if (!proc_unget_token(prep, tok)) { - printf("Error: failed to unget processor token\n"); + log_memory("failed to unget processor token\n"); // Empty destructor vector_del(types, args); goto failed; @@ -2378,7 +2450,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d // Empty destructor *tok = proc_next_token(prep); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) { - printf("Error: invalid token after function variadic argument\n"); + log_error(&tok->loginfo, "invalid token after function variadic argument\n"); proc_token_del(tok); vector_del(types, args); goto failed; @@ -2387,7 +2459,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } else { type_t *typ2 = type_new(); if (!typ2) { - printf("Error: failed to create new type (function argument)\n"); + log_memory("failed to create new type (function argument)\n"); // Empty destructor vector_del(types, args); goto failed; @@ -2403,7 +2475,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } if (spec2 == SPEC_NONE) { // _Static_assert declaration; empty destructor - printf("Invalid _Static_assert declaration\n"); + log_error(&tok->loginfo, "unexpected _Static_assert declaration\n"); vector_del(types, args); type_del(typ2); goto failed; @@ -2414,13 +2486,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d // Need to convert type to a pointer type_t *typ3 = type_new(); if (!typ3) { - printf("Error: failed to allocate new type\n"); + log_memory("failed to allocate new type\n"); type_del(typ2); // Empty destructor goto failed; } if (!type_copy_into(typ3, typ2)) { - printf("Error: failed to duplicate array type to temporary type\n"); + log_memory("failed to duplicate array type to temporary type\n"); type_del(typ3); type_del(typ2); // Empty destructor @@ -2432,7 +2504,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d typ2 = type_try_merge(typ3, PDECL_TYPE_SET); } if (!vector_push(types, args, typ2)) { - printf("Error: failed to add argument to argument vector\n"); + log_memory("failed to add argument to argument vector\n"); vector_del(types, args); type_del(typ2); // Empty destructor @@ -2445,13 +2517,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d // Need to convert type to a pointer type_t *typ3 = type_new(); if (!typ3) { - printf("Error: failed to allocate new type\n"); + log_memory("failed to allocate new type\n"); type_del(typ2); // Empty destructor goto failed; } if (!type_copy_into(typ3, typ2)) { - printf("Error: failed to duplicate array type to temporary type\n"); + log_memory("failed to duplicate array type to temporary type\n"); type_del(typ3); type_del(typ2); // Empty destructor @@ -2463,7 +2535,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d typ2 = type_try_merge(typ3, PDECL_TYPE_SET); } if (!vector_push(types, args, typ2)) { - printf("Error: failed to add argument to argument vector\n"); + log_memory("failed to add argument to argument vector\n"); vector_del(types, args); type_del(typ2); // Empty destructor @@ -2490,13 +2562,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } type_del(typ2); if (!dest2.argt.dest) { - printf("Internal error: argument type is NULL\n"); + log_internal(&tok->loginfo, "argument type is NULL\n"); vector_del(types, args); // Empty destructor goto failed; } if (!vector_push(types, args, dest2.argt.dest)) { - printf("Error: failed to add argument to argument vector\n"); + log_memory("failed to add argument to argument vector\n"); vector_del(types, args); type_del(dest2.argt.dest); // Empty destructor @@ -2509,7 +2581,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d *tok = proc_next_token(prep); continue; } - printf("Error: invalid token after function argument\n"); + log_error(&tok->loginfo, "invalid token after function argument\n"); vector_del(types, args); proc_token_del(tok); goto failed; @@ -2518,7 +2590,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d no_arg: new_typ = type_new(); if (!new_typ) { - printf("Error: failed to create new function type\n"); + log_memory("failed to create new function type\n"); // Empty destructor goto failed; } @@ -2547,7 +2619,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d break; } else { if (!vector_push(size_t, nptr_stack, 0)) { - printf("Failed to parse init_declarator_list (open parenthesis)\n"); + log_memory("Failed to push 0 to the nptr stack for opening a parenthesis\n"); // Empty destructor goto failed; } @@ -2556,13 +2628,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } } else if (tok->tokv.sym == SYM_STAR) { if (has_ident) { - printf("Error: invalid token '*' after identifier in declaration\n"); + log_error(&tok->loginfo, "invalid token '*' after identifier in declaration\n"); // Empty destructor goto failed; } else { type_t *new_typ = type_new_ptr(typ); if (!new_typ) { - printf("Failed to parse init_declarator_list (create new pointer typ)\n"); + log_memory("failed to create a new pointer type info structure\n"); // Empty destructor goto failed; } @@ -2574,14 +2646,14 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } else if (tok->tokv.sym == SYM_LSQBRACKET) { if (!has_ident) { if (!allow_abstract) { - printf("Error: invalid token '[' before identifier in declaration\n"); + log_error(&tok->loginfo, "invalid token '[' before identifier in declaration\n"); // Empty destructor goto failed; } has_ident = 1; } if (array_atomic || array_const || array_restrict || array_static || array_volatile) { - printf("Error: invalid array after array with type qualifier(s) and/or 'static'\n"); + log_error(&tok->loginfo, "invalid array after array with type qualifier(s) and/or 'static'\n"); // Empty destructor goto failed; } @@ -2598,10 +2670,10 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d size_t nelems; _Bool is_incomplete; while (1) { #define DO_CHECKS \ - if (is_init || is_list || !allow_decl || (cur_bottom && (typ->typ != TYPE_ARRAY))) { \ - printf("Error: type qualifiers and 'static' may only appear in function argument array declarations\n"); \ - /* Empty destructor */ \ - goto failed; \ + if (is_init || is_list || !allow_decl || (cur_bottom && (typ->typ != TYPE_ARRAY))) { \ + log_error(&tok->loginfo, "type qualifiers and 'static' may only appear in function argument array declarations\n"); \ + /* Empty destructor */ \ + goto failed; \ } if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ATOMIC)) { DO_CHECKS @@ -2629,7 +2701,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_RSQBRACKET)) { if (array_static) { // Missing expression - printf("Error: unexpected token ']' in static length array declaration\n"); + log_error(&tok->loginfo, "unexpected token ']' in static length array declaration\n"); // Empty destructor goto failed; } @@ -2639,7 +2711,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } else if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_STAR)) { if (array_static) { // Missing expression - printf("Error: unexpected token '*' in static length array declaration\n"); + log_error(&tok->loginfo, "unexpected token '*' in static length array declaration\n"); // Empty destructor goto failed; } @@ -2650,7 +2722,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d *tok = proc_next_token(prep); if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RSQBRACKET)) { // TODO: ...[*expr] - printf("Error: unexpected token during variable length array declaration\n"); + log_error(&tok->loginfo, "unexpected token during variable length array declaration\n"); proc_token_del(tok); goto failed; } @@ -2663,13 +2735,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d goto failed; } if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RSQBRACKET)) { - printf("Error: unexpected token during array declaration\n"); + log_error(&tok->loginfo, "unexpected token during array declaration\n"); expr_del(e); proc_token_del(tok); goto failed; } num_constant_t cst; - if (eval_expression(e, PDECL_CONST_MAP, &cst, is_init || is_list || !allow_decl)) { + if (eval_expression(&tok->loginfo, target, e, PDECL_CONST_MAP, &cst, is_init || is_list || !allow_decl)) { expr_del(e); int is_neg; switch (cst.typ) { @@ -2683,7 +2755,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d default: is_neg = 1; } if (is_neg) { - printf("Error: the size of an array must be nonnegative"); + log_error(&tok->loginfo, "the size of an array must be nonnegative"); // Empty destructor goto failed; } @@ -2702,7 +2774,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d if (cur_bottom) { type_t *tmp = type_new(); if (!tmp) { - printf("Failed to parse init_declarator_list (create new array type)\n"); + log_memory("failed to create new array type info\n"); // Empty destructor goto failed; } @@ -2721,7 +2793,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } else { type_t *new_typ = type_new(); if (!new_typ) { - printf("Failed to parse init_declarator_list (create new array type)\n"); + log_memory("failed to create new array type info\n"); // Empty destructor goto failed; } @@ -2737,7 +2809,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } else if (tok->tokv.sym == SYM_RPAREN) { if (!has_ident) { if (!allow_abstract) { - printf("Error: invalid token ')' before identifier in declaration\n"); + log_error(&tok->loginfo, "invalid token ')' before identifier in declaration\n"); // Empty destructor goto failed; } @@ -2745,7 +2817,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } if (vector_size(size_t, nptr_stack) == 1) { if (!is_init && !is_list) goto rparen_ok_ret; - printf("Error: closing unopened parenthesis in declaration\n"); + log_error(&tok->loginfo, "closing unopened parenthesis in declaration\n"); // Empty destructor goto failed; } @@ -2773,12 +2845,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d || (is_init && (tok->tokv.sym == SYM_LBRACKET))) { rparen_ok_ret: // Last function argument if (!allow_abstract && !has_ident) { - printf("Error: invalid symbol '%s' before identifier\n", sym2str[tok->tokv.sym]); + log_error(&tok->loginfo, "invalid symbol '%s' before identifier\n", sym2str[tok->tokv.sym]); // Empty destructor goto failed; } if (vector_size(size_t, nptr_stack) != 1) { - printf("Error: invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]); + log_error(&tok->loginfo, "invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]); // Empty destructor goto failed; } @@ -2786,7 +2858,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d // Try to free some redundant types typ = type_try_merge(typ, PDECL_TYPE_SET); - int validation = validate_storage_type(target, storage, typ, tok->tokv.sym); + int validation = validate_storage_type(&tok->loginfo, target, storage, typ, tok->tokv.sym); if (!validation) { // Empty destructor goto failed; @@ -2796,7 +2868,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d // Function definition; tok is '{' if (!is_init || !is_list || has_list) { // We are not at the top-level or we have an initialization list - printf("Error: invalid function definition\n"); + log_error(&tok->loginfo, "invalid function definition\n"); // Empty destructor goto failed; } @@ -2807,7 +2879,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d declaration_t *decl = malloc(sizeof *decl); if (!decl) { - printf("Failed to create new declaration\n"); + log_memory("failed to create new declaration\n"); // Empty destructor goto failed; } @@ -2819,7 +2891,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d char *cident = string_steal(cur_ident); cur_ident = NULL; khiter_t it = kh_put(decl_map, dest->f->decl_map, cident, &iret); if (iret < 0) { - printf("Failed to add function '%s' to the declaration map\n", cident); + log_memory("failed to add function '%s' to the declaration map\n", cident); free(cident); free(decl); // Empty destructor @@ -2827,7 +2899,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } else if (iret == 0) { free(decl); if (kh_val(dest->f->decl_map, it)->defined) { - printf("Error: function '%s' is already in the declaration map\n", cident); + log_error(&tok->loginfo, "function '%s' is already in the declaration map\n", cident); free(cident); // Empty destructor goto failed; @@ -2850,11 +2922,11 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d else goto success; } } while (!proc_token_isend(tok)); - printf("Error: unexpected token in function body\n"); + log_error(&tok->loginfo, "unexpected token in function body\n"); goto failed; } if ((fspec != FSPEC_NONE) && (typ->typ != TYPE_FUNCTION)) { - printf("Error: unexpected function specifier\n"); + log_error(&tok->loginfo, "unexpected function specifier\n"); // Empty destructor goto failed; } @@ -2863,7 +2935,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d if (storage == TMPSTO_TYPEDEF) { if (!is_init || !is_list) { // We are not at the top-level (note that storage is set to NONE in function arguments) - printf("Error: invalid function definition\n"); + log_error(&tok->loginfo, "invalid function definition\n"); // Empty destructor goto failed; } @@ -2872,13 +2944,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d char *cident = string_steal(cur_ident); cur_ident = NULL; khiter_t it = kh_put(type_map, dest->f->type_map, cident, &iret); if (iret < 0) { - printf("Failed to add '%s' to the type map\n", cident); + log_memory("failed to add '%s' to the type map\n", cident); free(cident); // Empty destructor goto failed; } else if (iret == 0) { if (!type_t_equal(typ, kh_val(dest->f->type_map, it))) { - printf("Error: '%s' is already in the type map with a different type\n", cident); + log_error(&tok->loginfo, "'%s' is already in the type map with a different type\n", cident); free(cident); type_del(typ); // Empty destructor @@ -2894,7 +2966,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d if (is_init && is_list) { decl = malloc(sizeof *decl); if (!decl) { - printf("Failed to create new declaration\n"); + log_memory("failed to create new declaration\n"); // Empty destructor goto failed; } @@ -2908,7 +2980,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d char *cident = string_steal(cur_ident); cur_ident = NULL; khiter_t it = kh_put(decl_map, dest->f->decl_map, cident, &iret); if (iret < 0) { - printf("Failed to add '%s' to the declaration map\n", cident); + log_memory("failed to add '%s' to the declaration map\n", cident); free(cident); free(decl); // Empty destructor @@ -2916,7 +2988,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } else if (iret == 0) { if (!type_t_equal(typ, kh_val(dest->f->decl_map, it)->typ) || ((storage == TMPSTO_NONE) && (kh_val(dest->f->decl_map, it)->storage == STORAGE_NONE))) { - printf("Error: '%s' is already in the declaration map (storage=%u)\n", cident, storage); + log_error(&tok->loginfo, "'%s' is already in the declaration map\n", cident); free(cident); free(decl); type_del(typ); @@ -2939,12 +3011,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d if (typ == base_type) { typ = type_new(); if (!typ) { - printf("Error: failed to allocate new type\n"); + log_memory("failed to allocate new type\n"); // Empty destructor goto failed; } if (!type_copy_into(typ, base_type)) { - printf("Error: failed to allocate new type\n"); + log_memory("failed to allocate new type\n"); // Empty destructor goto failed; } @@ -2963,13 +3035,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d goto success; } else if (!is_init && is_list) { if (!vector_push(st_members, dest->structms.dest, ((st_member_t){.name = cur_ident, .typ = typ, .is_bitfield = 0}))) { - printf("Error: failed to add structure member %s\n", string_content(cur_ident)); + log_memory("failed to add structure member %s\n", string_content(cur_ident)); string_del(cur_ident); // Empty destructor goto failed; } } else { - printf("Internal error: unknown is_init/is_list combination %d%d\n", is_init, is_list); + log_internal(&tok->loginfo, "unknown is_init/is_list combination %d%d\n", is_init, is_list); // Empty destructor goto failed; } @@ -2977,12 +3049,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_EQ)) { // Initialization if (!is_init) { - printf("Error: unexpected initializer\n"); + log_error(&tok->loginfo, "unexpected initializer\n"); goto failed; } if (decl) { if (decl->defined) { - printf("Error: invalid declaration initializer: variable was already declared\n"); + log_error(&tok->loginfo, "invalid declaration initializer: variable was already declared\n"); goto failed; } decl->defined = 1; @@ -3001,7 +3073,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } } while (!proc_token_isend(tok)); if (proc_token_isend(tok)) { - printf("Error: unexpected token in declaration initializer\n"); + log_error(&tok->loginfo, "unexpected token in declaration initializer\n"); proc_token_del(tok); goto failed; } @@ -3009,13 +3081,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d expr_t *e = parse_expression(target, PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS, PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, 15); if (!e) { - printf("Error: invalid declaration initializer\n"); + log_error(&tok->loginfo, "invalid declaration initializer\n"); goto failed; } expr_del(e); } if ((tok->tokt != PTOK_SYM) || ((tok->tokv.sym != SYM_COMMA) && (tok->tokv.sym != SYM_SEMICOLON))) { - printf("Error: unexpected token in declaration initializer\n"); + log_error(&tok->loginfo, "unexpected token in declaration initializer\n"); proc_token_del(tok); goto failed; } @@ -3032,7 +3104,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } } else if (!is_init && is_list && (tok->tokv.sym == SYM_COLON)) { if (vector_size(size_t, nptr_stack) != 1) { - printf("Error: invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]); + log_error(&tok->loginfo, "invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]); // Empty destructor goto failed; } @@ -3048,20 +3120,20 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d goto failed; } if ((tok->tokt != PTOK_SYM) || ((tok->tokv.sym != SYM_COMMA) && (tok->tokv.sym != SYM_SEMICOLON))) { - printf("Error: unexpected token in bitfield width\n"); + log_error(&tok->loginfo, "unexpected token in bitfield width\n"); expr_del(e); proc_token_del(tok); goto failed; } num_constant_t eval; - if (!eval_expression(e, dest->structms.const_map, &eval, 1)) { + if (!eval_expression(&tok->loginfo, target, e, dest->structms.const_map, &eval, 1)) { expr_del(e); // Empty destructor goto failed; } expr_del(e); - int validation = validate_storage_type(target, storage, typ, tok->tokv.sym); + int validation = validate_storage_type(&tok->loginfo, target, storage, typ, tok->tokv.sym); if (!validation) { // Empty destructor goto failed; @@ -3070,12 +3142,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d if (validation == VALIDATION_FUN) { // We are not at the top-level or we have an initialization list // Should never happen - printf("Error: invalid function definition in structure definition\n"); + log_error(&tok->loginfo, "invalid function definition in structure definition\n"); // Empty destructor goto failed; } if ((fspec != FSPEC_NONE) && (typ->typ != TYPE_FUNCTION)) { - printf("Error: unexpected function specifier\n"); + log_error(&tok->loginfo, "unexpected function specifier\n"); // Empty destructor goto failed; } @@ -3084,7 +3156,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d switch (eval.typ) { case NCT_INT32: if (eval.val.i32 < 0) { - printf("Error: invalid negative bitfield width\n"); + log_error(&tok->loginfo, "invalid negative bitfield width\n"); goto failed; } width = (size_t)eval.val.i32; @@ -3094,7 +3166,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d break; case NCT_INT64: if (eval.val.i64 < 0) { - printf("Error: invalid negative bitfield width\n"); + log_error(&tok->loginfo, "invalid negative bitfield width\n"); goto failed; } width = (size_t)eval.val.i64; @@ -3106,13 +3178,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d case NCT_DOUBLE: case NCT_LDOUBLE: default: - printf("Error: invalid non-integer bitfield width\n"); + log_error(&tok->loginfo, "invalid non-integer bitfield width\n"); goto failed; } if (!vector_push(st_members, dest->structms.dest, ((st_member_t){.name = cur_ident, .typ = typ, .is_bitfield = 1, .bitfield_width = width}))) { - printf("Error: failed to add structure member %s\n", string_content(cur_ident)); + log_memory("failed to add structure member %s\n", string_content(cur_ident)); string_del(cur_ident); // Empty destructor goto failed; @@ -3131,12 +3203,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d case PTOK_KEYWORD: if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ATOMIC)) { if (has_ident) { - printf("Error: invalid keyword '_Atomic' after identifier\n"); + log_error(&tok->loginfo, "invalid keyword '_Atomic' after identifier\n"); proc_token_print(tok); // Empty destructor goto failed; } else if (!vector_last(size_t, nptr_stack)) { - printf("Error: invalid keyword '_Atomic' before symbol '*'\n"); + log_error(&tok->loginfo, "invalid keyword '_Atomic' before symbol '*'\n"); proc_token_print(tok); // Empty destructor goto failed; @@ -3147,12 +3219,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_CONST)) { if (has_ident) { - printf("Error: invalid keyword 'const' after identifier\n"); + log_error(&tok->loginfo, "invalid keyword 'const' after identifier\n"); proc_token_print(tok); // Empty destructor goto failed; } else if (!vector_last(size_t, nptr_stack)) { - printf("Error: invalid keyword 'const' before symbol '*'\n"); + log_error(&tok->loginfo, "invalid keyword 'const' before symbol '*'\n"); proc_token_print(tok); // Empty destructor goto failed; @@ -3163,12 +3235,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_RESTRICT)) { if (has_ident) { - printf("Error: invalid keyword 'restrict' after identifier\n"); + log_error(&tok->loginfo, "invalid keyword 'restrict' after identifier\n"); proc_token_print(tok); // Empty destructor goto failed; } else if (!vector_last(size_t, nptr_stack)) { - printf("Error: invalid keyword 'restrict' before symbol '*'\n"); + log_error(&tok->loginfo, "invalid keyword 'restrict' before symbol '*'\n"); proc_token_print(tok); // Empty destructor goto failed; @@ -3179,12 +3251,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d } } else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_VOLATILE)) { if (has_ident) { - printf("Error: invalid keyword 'volatile' after identifier\n"); + log_error(&tok->loginfo, "invalid keyword 'volatile' after identifier\n"); proc_token_print(tok); // Empty destructor goto failed; } else if (!vector_last(size_t, nptr_stack)) { - printf("Error: invalid keyword 'volatile' before symbol '*'\n"); + log_error(&tok->loginfo, "invalid keyword 'volatile' before symbol '*'\n"); proc_token_print(tok); // Empty destructor goto failed; @@ -3200,13 +3272,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d case PTOK_STRING: case PTOK_PRAGMA: case PTOK_EOF: - printf("Error: unexpected token (parse_declarator %d%d%d%d)\n" - "Current state:\n" - " storage: %u\n" - " type: ", is_init, is_list, allow_decl, allow_abstract, storage); - type_print(typ); - printf("\n"); - proc_token_print(tok); + log_error(&tok->loginfo, "unexpected token (in parse_declarator %d%d%d%d)\n", is_init, is_list, allow_decl, allow_abstract); proc_token_del(tok); goto failed; } @@ -3226,44 +3292,44 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d static int finalize_file(machine_t *target, file_t *file) { #define MARK_SIMPLE(sname) \ - it = kh_get(struct_map, file->struct_map, #sname); \ - if (it != kh_end(file->struct_map)) { \ - kh_val(file->struct_map, it)->is_simple = 1; \ - } else { \ - it = kh_get(type_map, file->type_map, #sname); \ - if (it != kh_end(file->type_map)) { \ - type_t *typ2 = kh_val(file->type_map, it); \ - if (typ2->typ != TYPE_STRUCT_UNION) { \ - printf("Error: invalid typedef " #sname ": not a structure\n"); \ - return 0; \ - } \ - typ2->val.st->is_simple = 1; \ - } \ + it = kh_get(struct_map, file->struct_map, #sname); \ + if (it != kh_end(file->struct_map)) { \ + kh_val(file->struct_map, it)->is_simple = 1; \ + } else { \ + it = kh_get(type_map, file->type_map, #sname); \ + if (it != kh_end(file->type_map)) { \ + type_t *typ2 = kh_val(file->type_map, it); \ + if (typ2->typ != TYPE_STRUCT_UNION) { \ + log_error_nopos("invalid typedef " #sname ": not a structure\n"); \ + return 0; \ + } \ + typ2->val.st->is_simple = 1; \ + } \ } #define SET_WEAK(converted) \ - validate_type(target, typ); \ - typ = type_try_merge(typ, file->type_set); \ - it = kh_put(conv_map, file->relaxed_type_conversion, typ, &iret); \ - if (iret < 0) { \ - printf("Error: failed to add relaxed conversion to type map\n"); \ - type_del(typ); \ - return 0; \ - } else if (iret == 0) { \ - printf("Error: type already has a relaxed conversion\n"); \ - type_del(typ); \ - return 0; \ - } \ + validate_type(&(loginfo_t){0}, target, typ); \ + typ = type_try_merge(typ, file->type_set); \ + it = kh_put(conv_map, file->relaxed_type_conversion, typ, &iret); \ + if (iret < 0) { \ + log_memory("failed to add relaxed conversion to type map\n"); \ + type_del(typ); \ + return 0; \ + } else if (iret == 0) { \ + log_error_nopos("type already has a relaxed conversion\n"); \ + type_del(typ); \ + return 0; \ + } \ kh_val(file->relaxed_type_conversion, it) = string_new_cstr(#converted); #define SET_WEAK_PTR_TO(to_typ, converted) \ - it = kh_get(type_map, file->type_map, #to_typ); \ - if (it != kh_end(file->type_map)) { \ - typ = type_new_ptr(kh_val(file->type_map, it)); \ - if (!typ) { \ - printf("Failed to create type " #to_typ "*\n"); \ - return 0; \ - } \ - ++kh_val(file->type_map, it)->nrefs; \ - SET_WEAK(converted) \ + it = kh_get(type_map, file->type_map, #to_typ); \ + if (it != kh_end(file->type_map)) { \ + typ = type_new_ptr(kh_val(file->type_map, it)); \ + if (!typ) { \ + log_memory("failed to create type " #to_typ "*\n"); \ + return 0; \ + } \ + ++kh_val(file->type_map, it)->nrefs; \ + SET_WEAK(converted) \ } type_t *typ; @@ -3273,13 +3339,25 @@ static int finalize_file(machine_t *target, file_t *file) { SET_WEAK_PTR_TO(FILE, S) // #pragma type_letters b xcb_connection_t* SET_WEAK_PTR_TO(xcb_connection_t, S) + if (target->size_long == 4) { + // Only on x86, not on x86_64 + it = kh_get(type_map, file->type_map, "locale_t"); + if (it != kh_end(file->type_map)) { + typ = kh_val(file->type_map, it); + SET_WEAK(a) + } + } // #pragma mark_simple ... - MARK_SIMPLE(FTS) - MARK_SIMPLE(FTS64) - MARK_SIMPLE(glob_t) - MARK_SIMPLE(glob64_t) + if (target->size_long == 8) { + // Only on x86_64, not on x86 + MARK_SIMPLE(FTS) + MARK_SIMPLE(FTS64) + MARK_SIMPLE(glob_t) + MARK_SIMPLE(glob64_t) + } #undef MARK_SIMPLE #undef SET_WEAK +#undef SET_WEAK_PTR_TO return 1; } @@ -3287,20 +3365,20 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { char *dirname = strchr(filename, '/') ? strndup(filename, (size_t)(strrchr(filename, '/') - filename)) : NULL; preproc_t *prep = preproc_new_file(target, file, dirname, filename); if (!prep) { - printf("Failed to create the preproc structure\n"); + log_memory("failed to create the preproc structure\n"); if (dirname) free(dirname); return NULL; } file_t *ret = file_new(target); if (!ret) { - printf("Failed to create the file structure\n"); + log_memory("failed to create the file structure\n"); preproc_del(prep); return NULL; } type_t *typ = type_new(); if (!typ) { - printf("Failed to create a type info structure\n"); + log_memory("failed to create a type info structure\n"); goto failed; } while (1) { @@ -3315,17 +3393,17 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { int iret; char *dup = strdup(typenames[i]); if (!dup) { - printf("Failed to create a type info structure\n"); + log_memory("failed to create a type info structure\n"); goto failed; } type_t *t = ret->builtins[BTT_START_INT_EXT + i]; khiter_t it = kh_put(type_map, ret->type_map, dup, &iret); if (iret < 0) { - printf("Failed to add an intrinsic to the type map\n"); + log_memory("failed to add an intrinsic to the type map\n"); goto failed; } else if (iret == 0) { if (!type_t_equal(t, kh_val(ret->type_map, it))) { - printf("Error: %s is already defined\n", dup); + log_error(&tok.loginfo, "%s is already defined\n", dup); free(dup); goto failed; } @@ -3347,13 +3425,13 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { if (it != kh_end(ret->struct_map)) { type_t *typ2 = kh_val(ret->type_map, it); if (typ2->typ != TYPE_STRUCT_UNION) { - printf("Error: failed to find struct/union named %s\n", string_content(sutag)); + log_error(&tok.loginfo, "failed to find struct/union named %s\n", string_content(sutag)); string_del(sutag); goto failed; } su = typ2->val.st; } else { - printf("Error: failed to find struct/union named %s\n", string_content(sutag)); + log_error(&tok.loginfo, "failed to find struct/union named %s\n", string_content(sutag)); string_del(sutag); goto failed; } @@ -3366,7 +3444,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { string_t *converted = tok.tokv.pragma.val; type_t *typ2 = type_new(); if (!typ2) { - printf("Error: failed to create new type info structure\n"); + log_memory("failed to create new type info structure\n"); string_del(converted); type_del(typ2); goto failed; @@ -3380,13 +3458,13 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { int iret; khiter_t it = kh_put(conv_map, ret->relaxed_type_conversion, typ2, &iret); if (iret < 0) { - printf("Error: failed to add relaxed conversion to type map\n"); + log_memory("failed to add relaxed conversion to type map\n"); string_del(converted); type_del(typ2); // Empty destructor goto failed; } else if (iret == 0) { - printf("Error: type already has a relaxed conversion\n"); + log_error(&tok.loginfo, "type already has a relaxed conversion\n"); string_del(converted); type_del(typ2); // Empty destructor @@ -3400,7 +3478,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { string_t *converted = tok.tokv.pragma.val; type_t *typ2 = type_new(); if (!typ2) { - printf("Error: failed to create new type info structure\n"); + log_memory("failed to create new type info structure\n"); string_del(converted); type_del(typ2); goto failed; @@ -3413,7 +3491,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { } type_del(typ2); // typ2 is in the type set, so it is already used if (typ2->converted) { - printf("Error: type already has a strict conversion\n"); + log_error(&tok.loginfo, "type already has a strict conversion\n"); string_del(converted); // Empty destructor goto failed; @@ -3424,7 +3502,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { break; } } } else if (proc_token_iserror(&tok)) { - printf("Error: unexpected error token\n"); + log_error(&tok.loginfo, "unexpected error token\n"); proc_token_del(&tok); goto failed; } else { @@ -3442,11 +3520,11 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { goto failed; } } else { - if (validate_storage_type(target, storage, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) { + if (validate_storage_type(&tok.loginfo, target, storage, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) { goto failed; } if (fspec != FSPEC_NONE) { - printf("Error: unexpected function specifier\n"); + log_error(&tok.loginfo, "unexpected function specifier\n"); // Empty destructor goto failed; } @@ -3455,7 +3533,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { type_del(typ); typ = type_new(); if (!typ) { - printf("Failed to create a type info structure\n"); + log_memory("failed to create a type info structure\n"); goto failed; } } @@ -3465,7 +3543,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) { preproc_del(prep); type_del(typ); if (!finalize_file(target, ret)) { - printf("Error: failed to add builtin aliases\n"); + log_memory("failed to add builtin aliases\n"); file_del(ret); return NULL; } diff --git a/wrapperhelper/src/prepare.c b/wrapperhelper/src/prepare.c index 616f23323..ff19a0677 100644 --- a/wrapperhelper/src/prepare.c +++ b/wrapperhelper/src/prepare.c @@ -2,11 +2,17 @@ #include +typedef struct char_s { + int c; + loginfo_t li; +} char_t; + struct prepare_s { FILE *f; - int buf[4]; - int buf_len; // <= 4 (though 3 *should* be enough) + char_t buf[5]; + int buf_len; // <= 5 (though 4 *should* be enough) char *srcn; + loginfo_t li; enum prepare_state { PREPST_NONE = 0, PREPST_NL, @@ -21,14 +27,24 @@ struct prepare_s { prepare_t *prepare_new_file(FILE *f, const char *filename) { prepare_t *ret = malloc(sizeof *ret); if (!ret) { + log_memory("failed to allocate new preparator structure\n"); fclose(f); return NULL; } + + char *srcn = strdup(filename); + if (!srcn) { + log_memory("failed to duplicate filename\n"); + free(ret); + return NULL; + } + *ret = (prepare_t){ .f = f, - .buf = {0, 0, 0}, + .buf = {{0}, {0}, {0}, {0}}, .buf_len = 0, - .srcn = strdup(filename), + .srcn = srcn, + .li = { .filename = srcn, .lineno = 1, .colno = 1, .lineno_end = 0, .colno_end = 0 }, .st = PREPST_NL, }; return ret; @@ -40,28 +56,72 @@ void prepare_del(prepare_t *prep) { free(prep); } -static int get_char(prepare_t *src) { +// Do not call this more than twice in a row if the last character retrieved is '\\' +static void unget_char(prepare_t *src, char_t c) { + src->buf[src->buf_len++] = c; +} +// Transforms \n, \r\n and \r into \n +static char_t get_char(prepare_t *src) { + if (src->buf_len) { + return src->buf[--src->buf_len]; + } start_get_char: - int c = src->buf_len ? src->buf[--src->buf_len] : getc(src->f); - src->buf_len = 0; + int c = getc(src->f); if (c == '\\') { - c = src->buf_len ? src->buf[--src->buf_len] : getc(src->f); - if (c == '\n') goto start_get_char; - src->buf[src->buf_len++] = c; - return '\\'; + c = getc(src->f); + if (c == '\n') { + ++src->li.lineno; + src->li.colno = 1; + goto start_get_char; + } else if (c == '\r') { + ++src->li.lineno; + src->li.colno = 1; + c = getc(src->f); + if (c == '\n') { + goto start_get_char; + } else { + unget_char(src, (char_t){.c = c, .li = src->li}); + goto start_get_char; + } + } + src->li.colno += 2; + src->buf[src->buf_len++] = (char_t){ + .c = c, + .li = { .filename = src->li.filename, .lineno = src->li.lineno, .colno = src->li.colno - 1, .lineno_end = 0, .colno_end = 0 } + }; + return (char_t){ + .c = '\\', + .li = { .filename = src->li.filename, .lineno = src->li.lineno, .colno = src->li.colno - 2, .lineno_end = 0, .colno_end = 0 } + }; } - return c; -} -// Do not call this more than twice in a row if the last character retrieved is '\\' -static void unget_char(prepare_t *src, int c) { - src->buf[src->buf_len++] = c; + char_t ret = { + .c = c, + .li = { .filename = src->li.filename, .lineno = src->li.lineno, .colno = src->li.colno, .lineno_end = 0, .colno_end = 0 } + }; + if (c == '\n') { + ++src->li.lineno; + src->li.colno = 1; + } else if (c == '\r') { + ++src->li.lineno; + src->li.colno = 1; + ret.c = '\n'; + c = getc(src->f); + if (c != '\n') { + unget_char(src, (char_t){.c = c, .li = src->li}); + } + } else { + ++src->li.colno; + } + return ret; } -static void fill_ident(prepare_t *src, string_t *buf) { +static void fill_ident(prepare_t *src, string_t *buf, size_t *lineno_end, size_t *colno_end) { while (1) { - int c = get_char(src); - if ((c == '_') || ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) { - string_add_char(buf, (char)c); + char_t c = get_char(src); + if ((c.c == '_') || ((c.c >= '0') && (c.c <= '9')) || ((c.c >= 'A') && (c.c <= 'Z')) || ((c.c >= 'a') && (c.c <= 'z'))) { + string_add_char(buf, (char)c.c); + *lineno_end = c.li.lineno; + *colno_end = c.li.colno; } else { unget_char(src, c); return; @@ -69,14 +129,16 @@ static void fill_ident(prepare_t *src, string_t *buf) { } } -static void fill_num(prepare_t *src, string_t *buf) { +static void fill_num(prepare_t *src, string_t *buf, size_t *lineno_end, size_t *colno_end) { int started_exp = 0; while (1) { - int c = get_char(src); - if ((c == '_') || (c == '.') || ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) - || (started_exp && ((c == '+') || (c == '-')))) { - started_exp = (c == 'e') || (c == 'E') || (c == 'p') || (c == 'P'); - string_add_char(buf, (char)c); + char_t c = get_char(src); + if ((c.c == '_') || (c.c == '.') || ((c.c >= '0') && (c.c <= '9')) || ((c.c >= 'A') && (c.c <= 'Z')) || ((c.c >= 'a') && (c.c <= 'z')) + || (started_exp && ((c.c == '+') || (c.c == '-')))) { + started_exp = (c.c == 'e') || (c.c == 'E') || (c.c == 'p') || (c.c == 'P'); + string_add_char(buf, (char)c.c); + *lineno_end = c.li.lineno; + *colno_end = c.li.colno; } else { unget_char(src, c); return; @@ -84,32 +146,42 @@ static void fill_num(prepare_t *src, string_t *buf) { } } -static void fill_str(prepare_t *src, string_t *buf, char end_c, int can_esc) { +static void fill_str(prepare_t *src, string_t *buf, char end_c, int can_esc, size_t *lineno_end, size_t *colno_end) { int has_esc = 0; while (1) { - int c = get_char(src); - if (has_esc && (c >= 0) && (c <= 0x7F) && (c != '\n')) { + char_t c = get_char(src); + if (has_esc && (c.c >= 0) && (c.c <= 0x7F) && (c.c != '\n')) { // Not technically standard compliant (should support \ooo, \x..., \u..., \U...) // Since we don't really care about parsing the content, only the delimiters, this is good enough string_add_char(buf, '\\'); - string_add_char(buf, (char)c); + string_add_char(buf, (char)c.c); has_esc = 0; - } else if (c == '\\') { + *lineno_end = c.li.lineno; + *colno_end = c.li.colno; + } else if (c.c == '\\') { + *lineno_end = c.li.lineno; + *colno_end = c.li.colno; if (can_esc) { has_esc = 1; } else { string_add_char(buf, '\\'); } - } else if ((c >= 0) && (c <= 0x7F) && (c != '\n') && (c != end_c)) { + } else if ((c.c >= 0) && (c.c <= 0x7F) && (c.c != '\n') && (c.c != end_c)) { has_esc = 0; - string_add_char(buf, (char)c); + string_add_char(buf, (char)c.c); + *lineno_end = c.li.lineno; + *colno_end = c.li.colno; } else { + // c.c is invalid (> 0x80) or a '\n', or can_esc = 0 and c.c = end_c if (has_esc) { - // c is invalid or a '\n', or can_esc = 0 and c = end_c string_add_char(buf, '\\'); } - if (c != end_c) + if (c.c != end_c) { unget_char(src, c); + } else { + *lineno_end = c.li.lineno; + *colno_end = c.li.colno; + } return; } } @@ -157,42 +229,47 @@ static const struct symbs_s { preproc_token_t pre_next_token(prepare_t *src, int allow_comments) { if (src->st == PREPST_COMMENT) { // In comments, keep everything as 'BLANK' except for idents, newlines and EOF - int c = get_char(src); - if (c == EOF) { + char_t c = get_char(src); + if (c.c == EOF) { // Force newline at EOF unget_char(src, c); src->st = PREPST_NL; return (preproc_token_t){ .tokt = PPTOK_NEWLINE, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; - } else if ((c == '_') || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) { + } else if ((c.c == '_') || ((c.c >= 'a') && (c.c <= 'z')) || ((c.c >= 'A') && (c.c <= 'Z'))) { preproc_token_t ret; ret.tokt = PPTOK_IDENT; + ret.loginfo = c.li; ret.tokv.str = string_new_cap(1); - string_add_char(ret.tokv.str, (char)c); - fill_ident(src, ret.tokv.str); + string_add_char(ret.tokv.str, (char)c.c); + fill_ident(src, ret.tokv.str, &ret.loginfo.lineno_end, &ret.loginfo.colno_end); return ret; - } else if ((c >= 0) && (c <= 0x7F)) { + } else if ((c.c >= 0) && (c.c <= 0x7F)) { return (preproc_token_t){ .tokt = PPTOK_BLANK, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; } else { return (preproc_token_t){ .tokt = PPTOK_INVALID, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; } } start_next_token: - int c = get_char(src); - if (c == EOF) { + char_t c = get_char(src); + if (c.c == EOF) { if (src->st == PREPST_NL) { return (preproc_token_t){ .tokt = PPTOK_EOF, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; } else { // Force newline at EOF @@ -200,60 +277,67 @@ preproc_token_t pre_next_token(prepare_t *src, int allow_comments) { src->st = PREPST_NL; return (preproc_token_t){ .tokt = PPTOK_NEWLINE, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; } } - if (src->st == PREPST_INCL && (c == '<')) { + if (src->st == PREPST_INCL && (c.c == '<')) { src->st = PREPST_NONE; preproc_token_t ret; ret.tokt = PPTOK_INCL; + ret.loginfo = c.li; ret.tokv.sisstr = 0; ret.tokv.sstr = string_new(); - fill_str(src, ret.tokv.sstr, '>', 0); + fill_str(src, ret.tokv.sstr, '>', 0, &ret.loginfo.lineno_end, &ret.loginfo.colno_end); return ret; } - if (c == '\'') { + if (c.c == '\'') { src->st = PREPST_NONE; preproc_token_t ret; ret.tokt = PPTOK_STRING; + ret.loginfo = c.li; ret.tokv.sisstr = 0; ret.tokv.sstr = string_new_cap(1); // Usually only one character is inside a char literal - fill_str(src, ret.tokv.sstr, '\'', 1); + fill_str(src, ret.tokv.sstr, '\'', 1, &ret.loginfo.lineno_end, &ret.loginfo.colno_end); return ret; } - if (c == '"') { + if (c.c == '"') { preproc_token_t ret; ret.tokt = (src->st == PREPST_INCL) ? PPTOK_INCL : PPTOK_STRING; src->st = PREPST_NONE; + ret.loginfo = c.li; ret.tokv.sisstr = 1; ret.tokv.sstr = string_new(); - fill_str(src, ret.tokv.sstr, '"', ret.tokt == PPTOK_STRING); + fill_str(src, ret.tokv.sstr, '"', ret.tokt == PPTOK_STRING, &ret.loginfo.lineno_end, &ret.loginfo.colno_end); return ret; } - if ((c == ' ') || (c == '\f') || (c == '\t') || (c == '\v')) { + if ((c.c == ' ') || (c.c == '\f') || (c.c == '\t') || (c.c == '\v')) { if (src->st == PREPST_DEFID) { src->st = PREPST_NONE; return (preproc_token_t){ .tokt = PPTOK_BLANK, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; } else goto start_next_token; } - if (c == '\n') { + if (c.c == '\n') { src->st = PREPST_NL; return (preproc_token_t){ .tokt = PPTOK_NEWLINE, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; } - if ((c == '_') || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) { + if ((c.c == '_') || ((c.c >= 'a') && (c.c <= 'z')) || ((c.c >= 'A') && (c.c <= 'Z'))) { preproc_token_t ret; ret.tokt = PPTOK_IDENT; + ret.loginfo = c.li; ret.tokv.str = string_new_cap(1); - string_add_char(ret.tokv.str, (char)c); - fill_ident(src, ret.tokv.str); + string_add_char(ret.tokv.str, (char)c.c); + fill_ident(src, ret.tokv.str, &ret.loginfo.lineno_end, &ret.loginfo.colno_end); src->st = ((src->st == PREPST_HASH) && (!strcmp(string_content(ret.tokv.str), "include"))) ? PREPST_INCL : ((src->st == PREPST_HASH) && (!strcmp(string_content(ret.tokv.str), "include_next"))) ? PREPST_INCL : @@ -262,107 +346,131 @@ preproc_token_t pre_next_token(prepare_t *src, int allow_comments) { PREPST_NONE; return ret; } - if ((c >= '0') && (c <= '9')) { + if ((c.c >= '0') && (c.c <= '9')) { src->st = PREPST_NONE; preproc_token_t ret; ret.tokt = PPTOK_NUM; + ret.loginfo = c.li; ret.tokv.str = string_new_cap(1); - string_add_char(ret.tokv.str, (char)c); - fill_num(src, ret.tokv.str); + string_add_char(ret.tokv.str, (char)c.c); + fill_num(src, ret.tokv.str, &ret.loginfo.lineno_end, &ret.loginfo.colno_end); return ret; } - if (c == '.') { + if (c.c == '.') { + loginfo_t oldli = c.li; c = get_char(src); - if ((c >= '0') && (c <= '9')) { + if ((c.c >= '0') && (c.c <= '9')) { src->st = PREPST_NONE; preproc_token_t ret; ret.tokt = PPTOK_NUM; + ret.loginfo = oldli; + ret.loginfo.lineno_end = c.li.lineno; + ret.loginfo.colno_end = c.li.colno; ret.tokv.str = string_new_cap(2); string_add_char(ret.tokv.str, '.'); - string_add_char(ret.tokv.str, (char)c); - fill_num(src, ret.tokv.str); + string_add_char(ret.tokv.str, (char)c.c); + fill_num(src, ret.tokv.str, &ret.loginfo.lineno_end, &ret.loginfo.colno_end); return ret; } else { unget_char(src, c); - c = '.'; + c.c = '.'; + c.li = oldli; } } - if (c == '/') { - c = get_char(src); - if (c == '/') { + if (c.c == '/') { + char_t c2 = get_char(src); + if (c2.c == '/') { if (allow_comments) { src->st = PREPST_COMMENT; return (preproc_token_t){ .tokt = PPTOK_START_LINE_COMMENT, - .tokv.c = '/' + .loginfo = { + .filename = c2.li.filename, + .lineno = c.li.lineno, .colno = c.li.colno, + .lineno_end = c2.li.lineno, .colno_end = c2.li.colno, + }, + .tokv.c = '/', }; } do { - c = get_char(src); - } while ((c != EOF) && (c != '\n')); - if (c != EOF) { + c2 = get_char(src); + } while ((c2.c != EOF) && (c2.c != '\n')); + if (c2.c != EOF) { if (src->st == PREPST_NL) goto start_next_token; else { src->st = PREPST_NL; return (preproc_token_t){ .tokt = PPTOK_NEWLINE, - .tokv.c = (char)c + .loginfo = c2.li, + .tokv.c = (char)c2.c }; } } - src->st = PREPST_NONE; - printf("Unfinished comment while preparing %s\n", src->srcn); + // Force newline at EOF + unget_char(src, c2); + src->st = PREPST_NL; return (preproc_token_t){ - .tokt = PPTOK_INVALID, - .tokv.c = (char)c + .tokt = PPTOK_NEWLINE, + .loginfo = c2.li, + .tokv.c = (char)c2.c }; - } else if (c == '*') { + } else if (c2.c == '*') { if (allow_comments) { - printf("Unsupported multiline comment with allow_comment in %s\n", src->srcn); + c.li.lineno_end = c2.li.lineno; + c.li.colno_end = c2.li.colno; + log_error(&c.li, "unsupported multiline comment with allow_comment\n"); return (preproc_token_t){ .tokt = PPTOK_INVALID, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c }; } - c = get_char(src); + c2 = get_char(src); int last_star = 0; - while ((c != EOF) && (!last_star || (c != '/'))) { - last_star = c == '*'; - c = get_char(src); + while ((c2.c != EOF) && (!last_star || (c2.c != '/'))) { + last_star = c2.c == '*'; + c2 = get_char(src); } - if (c != EOF) goto start_next_token; + if (c2.c != EOF) goto start_next_token; + c.li.lineno_end = c2.li.lineno; + c.li.colno_end = c2.li.colno; + log_error(&c.li, "unfinished multiline comment\n"); src->st = PREPST_NONE; - printf("Unfinished comment while preparing %s\n", src->srcn); return (preproc_token_t){ .tokt = PPTOK_INVALID, - .tokv.c = (char)c + .loginfo = c2.li, + .tokv.c = (char)c2.c }; } else { - unget_char(src, c); - c = '/'; + unget_char(src, c2); } } struct symbs_s const *sym = NULL; for (int i = 0; i < BASE_NSYMS; ++i) { - if (c == symbs[i].c) { + if (c.c == symbs[i].c) { sym = &symbs[i]; break; } } if (sym) { + loginfo_t lisym = c.li; + loginfo_t liend = c.li; while (sym->nnext) { c = get_char(src); int found = 0; for (int i = 0; i < sym->nnext; ++i) { - if (c == sym->next[i].c) { + if (c.c == sym->next[i].c) { found = 1; sym = &sym->next[i]; + liend = c.li; + lisym.lineno_end = c.li.lineno; + lisym.colno_end = c.li.colno; break; } } @@ -372,41 +480,66 @@ preproc_token_t pre_next_token(prepare_t *src, int allow_comments) { } } if (sym->sym == LAST_SYM + 1) { - unget_char(src, sym->c); - sym = &symbs[0]; // This is where no check is made (see comment in the definition of symbs) + // This is where no check is made (see comment in the definition of symbs) + unget_char(src, (char_t){.c = sym->c, .li = liend}); + sym = &symbs[0]; + lisym.lineno_end = lisym.colno_end = 0; } src->st = ((src->st == PREPST_NL) && (sym->sym == SYM_HASH)) ? PREPST_HASH : PREPST_NONE; return (preproc_token_t){ .tokt = PPTOK_SYM, + .loginfo = lisym, .tokv.sym = sym->sym }; } src->st = PREPST_NONE; - printf("Invalid character 0x%X (%c) while preparing %s\n", (unsigned)c, (c >= 0x20) && (c < 127) ? c : '?', src->srcn); + log_error(&c.li, "invalid character 0x%02X (%c)\n", (unsigned)c.c, (c.c >= 0x20) && (c.c < 0x7F) ? c.c : '?'); return (preproc_token_t){ .tokt = PPTOK_INVALID, - .tokv.c = (char)c + .loginfo = c.li, + .tokv.c = (char)c.c, }; } +void prepare_set_line(prepare_t *src, char *filename, size_t lineno) { + if (filename) { + if (src->srcn) free(filename); + src->srcn = filename; + src->li.filename = filename; + } + size_t colno = 1; + for (int i = src->buf_len; i--; ) { + src->buf[i].li.lineno = lineno; + src->buf[i].li.colno = colno; + if (src->buf[i].c == '\n') { + ++lineno; + colno = 1; + } else { + ++colno; + } + } + src->li.lineno = lineno; + src->li.colno = colno; +} + // Warning: unsafe method void prepare_mark_nocomment(prepare_t *src) { src->st = PREPST_NONE; } int pre_next_newline_token(prepare_t *src, string_t *buf) { while (1) { - int c = get_char(src); - if (c == EOF) { + char_t c = get_char(src); + if (c.c == EOF) { // Force newline at EOF unget_char(src, c); src->st = PREPST_NL; return 1; - } else if (c == '\n') { + } else if (c.c == '\n') { src->st = PREPST_NL; return 1; - } else if ((c >= 0) && (c <= 0x7F)) { - if (!string_add_char(buf, (char)c)) return 0; + } else if ((c.c >= 0) && (c.c <= 0x7F)) { + if (!string_add_char(buf, (char)c.c)) return 0; } else { return 0; } diff --git a/wrapperhelper/src/prepare.h b/wrapperhelper/src/prepare.h index c84242610..9192fc781 100644 --- a/wrapperhelper/src/prepare.h +++ b/wrapperhelper/src/prepare.h @@ -14,6 +14,8 @@ prepare_t *prepare_new_file(FILE *f, const char *filename); // Takes ownership o void prepare_del(prepare_t *src); preproc_token_t pre_next_token(prepare_t *src, int allow_comments); +void prepare_set_line(prepare_t *src, char *filename, size_t lineno); // Takes ownership of filename if != NULL + void prepare_mark_nocomment(prepare_t *src); // Change the state (usually from COMMENT) to NONE int pre_next_newline_token(prepare_t *src, string_t *buf); // In a comment append everything until the EOL or EOF to the buffer diff --git a/wrapperhelper/src/preproc.c b/wrapperhelper/src/preproc.c index bbef68446..10ac978b2 100644 --- a/wrapperhelper/src/preproc.c +++ b/wrapperhelper/src/preproc.c @@ -10,6 +10,10 @@ #include "machine.h" #include "prepare.h" +//#define LOG_OPEN +//#define LOG_INCLUDE +//#define LOG_CLOSE + typedef struct mtoken_s { enum mtoken_e { MTOK_TOKEN, @@ -79,7 +83,7 @@ static mtoken_t *mtoken_new_concat(mtoken_t *l, mtoken_t *r) { // Takes ownershi return ret; } -static inline void print_macro_tok(mtoken_t *m) { +static inline void macro_tok_print(mtoken_t *m) { switch (m->typ) { case MTOK_TOKEN: printf("token type %u", m->val.tok.tokt); @@ -94,9 +98,9 @@ static inline void print_macro_tok(mtoken_t *m) { case MTOK_CONCAT: printf("concat {"); - print_macro_tok(m->val.concat.l); + macro_tok_print(m->val.concat.l); printf("} {"); - print_macro_tok(m->val.concat.r); + macro_tok_print(m->val.concat.r); printf("}"); return; @@ -261,7 +265,9 @@ static int try_open_dir(preproc_t *src, string_t *filename) { } strcpy(fn + incl_len + 1, string_content(filename)); FILE *f = fopen(fn, "r"); - // printf("Trying %s: %p\n", fn, f); +#ifdef LOG_OPEN + printf("Trying %s: %p\n", fn, f); +#endif int ret; if (f) { char *new_dirname = strchr(fn, '/') ? strndup(fn, (size_t)(strrchr(fn, '/') - fn)) : NULL; @@ -288,7 +294,9 @@ static int try_open_sys(preproc_t *src, string_t *filename, size_t array_off) { fn[incl_len] = '/'; strcpy(fn + incl_len + 1, string_content(filename)); FILE *f = fopen(fn, "r"); - // printf("Trying %s: %p\n", fn, f); +#ifdef LOG_OPEN + printf("Trying %s: %p\n", fn, f); +#endif if (f) { char *new_dirname = strchr(fn, '/') ? strndup(fn, (size_t)(strrchr(fn, '/') - fn)) : NULL; int ret = vector_push(ppsource, src->prep, PREPARE_NEW_FILE(f, fn, src->cur_file, src->dirname, src->is_sys, src->cur_pathno)); @@ -365,12 +373,12 @@ preproc_t *preproc_new_file(machine_t *target, FILE *f, char *dirname, const cha // Also include 'stdc-predef.h' (it will be parsed before the requested file) string_t *stdc_predef = string_new_cstr("stdc-predef.h"); if (!stdc_predef) { - printf("Error: failed to create new string 'stdc-predef.h'\n"); + log_memory("failed to create new string 'stdc-predef.h'\n"); preproc_del(ret); return NULL; } if (!try_open_sys(ret, stdc_predef, 0)) { - printf("Error: failed to open file 'stdc-predef.h'\n"); + log_error_nopos("failed to open file 'stdc-predef.h'\n"); string_del(stdc_predef); preproc_del(ret); return NULL; @@ -387,22 +395,24 @@ static void preprocs_del(VECTOR(preproc) **p) { VECTOR_DECLARE_STATIC(preprocs, VECTOR(preproc)*) VECTOR_IMPL_STATIC(preprocs, preprocs_del) -static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const VECTOR(preproc) *toks, - khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros); +static VECTOR(preproc) *preproc_do_expand(loginfo_t *li, const khash_t(macros_map) *macros, const VECTOR(preproc) *toks, + khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros); // Does not take any ownership, returns a vector with independent ownerships // opt_used_macros is NULL in regular expansion, non-NULL in #if-expansions -static VECTOR(preproc) * - proc_solve_macro(const khash_t(macros_map) *macros, char *mname, const macro_t *m, VECTOR(preprocs) *margs, - khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros); +static VECTOR(preproc) *preproc_solve_macro(loginfo_t *li, + const khash_t(macros_map) *macros, char *mname, const macro_t *m, VECTOR(preprocs) *margs, + khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros); // Moves mname to solved_macros or frees mname, returns a vector with independent ownerships // margs may be NULL if m->is_funlike is false // May change margs if m->has_varargs, but takes no ownership // opt_used_macros is NULL in regular expansion, non-NULL in #if-expansions -static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char *mname, const macro_t *m, VECTOR(preprocs) *margs, - khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros) { +static VECTOR(preproc) *preproc_solve_macro(loginfo_t *li, + const khash_t(macros_map) *macros, char *mname, const macro_t *m, VECTOR(preprocs) *margs, + khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros) { +#define LOG_MEMORY(fmt, ...) log_memory(fmt " while expanding %s\n" __VA_ARGS__, mname) if (m->is_funlike && !margs) { - printf("is_funlike && !margs>\n"); + log_internal(li, "m->is_funlike && !margs in preproc_solve_macro(... %s ...)\n", mname); free(mname); return NULL; } @@ -410,7 +420,7 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char && (m->nargs != vector_size(preprocs, margs)) // General case && (!m->has_varargs || (m->nargs > vector_size(preprocs, margs))) // Variadics && (m->nargs || ((vector_size(preprocs, margs) == 1) && (vector_size(preproc, vector_last(preprocs, margs)) == 0)))) { // Zero argument - printf("Invalid argument count for macro %s\n", mname); + log_error(li, "invalid argument count for macro %s\n", mname); free(mname); return NULL; } @@ -420,12 +430,12 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char // No varargs, so add an empty one VECTOR(preproc) *marg = vector_new(preproc); if (!marg) { - printf("Failed to create __VA_ARGS__ while expanding %s\n", mname); + LOG_MEMORY("failed to create __VA_ARGS__"); free(mname); return NULL; } if (!vector_push(preprocs, margs, marg)) { - printf("Failed to add __VA_ARGS__ while expanding %s\n", mname); + LOG_MEMORY("failed to add __VA_ARGS__"); vector_del(preproc, marg); free(mname); return NULL; @@ -436,13 +446,13 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char size_t size0 = vector_size(preproc, mvarg); vector_for_from(preprocs, it, margs, m->nargs + 1) { if (!vector_push(preproc, mvarg, ((preproc_token_t){.tokt = PPTOK_SYM, .tokv.sym = SYM_COMMA}))) { - printf("Failed to add comma to __VA_ARGS__ while expanding %s\n", mname); + LOG_MEMORY("failed to add comma to __VA_ARGS__"); vector_pop_nodel_slice(preproc, mvarg, vector_size(preproc, mvarg) - size0); free(mname); return NULL; } if (!vector_push_vec(preproc, mvarg, *it)) { - printf("Failed to add extra argument to __VA_ARGS__ while expanding %s\n", mname); + LOG_MEMORY("failed to add extra argument to __VA_ARGS__"); vector_pop_nodel_slice(preproc, mvarg, vector_size(preproc, mvarg) - size0); free(mname); return NULL; @@ -453,13 +463,13 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char // Avoid 0-allocations VECTOR(preproc) **margs2 = calloc(margs ? (vector_size(preprocs, margs) ? vector_size(preprocs, margs) : 1) : 1, sizeof *margs2); if (!margs2) { - printf("Memory error while expanding %s\n", mname); + LOG_MEMORY("failed to allocate expanded arguments array"); free(mname); return NULL; } VECTOR(preproc) *ret = vector_new(preproc); if (!ret) { - printf("Memory error while expanding %s\n", mname); + LOG_MEMORY("failed to allocate return vector"); free(margs2); free(mname); return NULL; @@ -467,7 +477,7 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char VECTOR(mtoken) *st = vector_new_cap(mtoken, vector_size(mtoken, m->toks)); if (!st) { - printf("Memory error while expanding %s\n", mname); + LOG_MEMORY("failed to allocate auxiliary vector"); vector_del(preproc, ret); free(margs2); free(mname); @@ -483,6 +493,7 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char case MTOK_CONCAT: { vector_last(mtoken, st) = mtok->val.concat.r; if (!vector_push(mtoken, st, mtok->val.concat.l)) { + LOG_MEMORY("failed to add concatenation left m-token"); vector_del(preproc, ret); ret = NULL; goto solve_done; @@ -495,20 +506,32 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char if (concat_cur == 2) { preproc_token_t *tok1 = &vector_last(preproc, ret); // Guaranteed to exist preproc_token_t *tok2 = &mtok->val.tok; - if (((tok1->tokt == PPTOK_IDENT) || (tok1->tokt == PPTOK_IDENT_UNEXP) || (tok1->tokt == PPTOK_NUM)) - && ((tok2->tokt == PPTOK_IDENT) || (tok2->tokt == PPTOK_IDENT_UNEXP) || (tok2->tokt == PPTOK_NUM))) { +#define ISIDENT(tt) (((tt) == PPTOK_IDENT) || ((tt) == PPTOK_IDENT_UNEXP)) +#define FIND(s, c) strchr(string_content((s)), (c)) +#define ONLYDIGS(s) (!FIND((s), '.') && !FIND((s), '+') && !FIND((s), '-')) + if (ISIDENT(tok1->tokt) && (ISIDENT(tok2->tokt) || ((tok2->tokt == PPTOK_NUM) && ONLYDIGS(tok2->tokv.str)))) { + do_add = 0; + tok1->tokt = PPTOK_IDENT; + if (!string_add_string(tok1->tokv.str, tok2->tokv.str)) { + LOG_MEMORY("failed to concatenate identifiers"); + vector_del(preproc, ret); + ret = NULL; + goto solve_done; + } + } else if ((tok1->tokt == PPTOK_NUM) && (ISIDENT(tok2->tokt) || (tok2->tokt == PPTOK_NUM))) { do_add = 0; - // TODO: check if concat is possible, what behaviour should be in the case below - if (tok1->tokt == PPTOK_IDENT_UNEXP) tok1->tokt = PPTOK_IDENT; if (!string_add_string(tok1->tokv.str, tok2->tokv.str)) { - printf("Memory error while expanding %s\n", mname); + LOG_MEMORY("failed to concatenate identifiers"); vector_del(preproc, ret); ret = NULL; goto solve_done; } } else { - printf("Warning: unsupported concatenation between token type %u and %u while expanding %s\n", tok1->tokt, tok2->tokt, mname); + log_warning(li, "unsupported concatenation between token type %u and %u while expanding %s\n", tok1->tokt, tok2->tokt, mname); } +#undef ISIDENT +#undef FIND +#undef ONLYDIGS } if (do_add) { preproc_token_t tok2; @@ -518,33 +541,34 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char case PPTOK_NEWLINE: case PPTOK_BLANK: case PPTOK_START_LINE_COMMENT: - case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.c = tok1->tokv.c}; break; - case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.sym = tok1->tokv.sym}; break; + case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.c = tok1->tokv.c}; break; + case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sym = tok1->tokv.sym}; break; case PPTOK_IDENT: case PPTOK_IDENT_UNEXP: case PPTOK_NUM: { string_t *dup = string_dup(tok1->tokv.str); if (!dup) { - printf("Failed to duplicate string while expanding %s\n", mname); + LOG_MEMORY("failed to duplicate string"); vector_del(preproc, ret); ret = NULL; goto solve_done; } - tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.str = dup}; + tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.str = dup}; break; } case PPTOK_INCL: case PPTOK_STRING: { string_t *dup = string_dup(tok1->tokv.sstr); if (!dup) { - printf("Failed to duplicate string while expanding %s\n", mname); + LOG_MEMORY("failed to duplicate string"); vector_del(preproc, ret); ret = NULL; goto solve_done; } - tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.sstr = dup, .tokv.sisstr = tok1->tokv.sisstr}; + tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sstr = dup, .tokv.sisstr = tok1->tokv.sisstr}; break; } } if (!vector_push(preproc, ret, tok2)) { + LOG_MEMORY("failed to add token to output vector"); preproc_token_del(&tok2); vector_del(preproc, ret); ret = NULL; @@ -562,7 +586,12 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char VECTOR(preproc) *toks_to_add; if (!need_concat && !concat_cur) { if (!margs2[mtok->val.argid]) { - margs2[mtok->val.argid] = proc_do_expand(macros, vector_content(preprocs, margs)[mtok->val.argid], solved_macros, opt_used_macros); + margs2[mtok->val.argid] = preproc_do_expand(li, macros, vector_content(preprocs, margs)[mtok->val.argid], solved_macros, opt_used_macros); + if (!margs2[mtok->val.argid]) { + vector_del(preproc, ret); + ret = NULL; + goto solve_done; + } } toks_to_add = margs2[mtok->val.argid]; } else { @@ -572,20 +601,32 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char if (len && (concat_cur == 2)) { preproc_token_t *tok1 = &vector_last(preproc, ret); // Guaranteed to exist preproc_token_t *tok2 = vector_begin(preproc, toks_to_add); - if (((tok1->tokt == PPTOK_IDENT) || (tok1->tokt == PPTOK_IDENT_UNEXP) || (tok1->tokt == PPTOK_NUM)) - && ((tok2->tokt == PPTOK_IDENT) || (tok2->tokt == PPTOK_IDENT_UNEXP) || (tok2->tokt == PPTOK_NUM))) { +#define ISIDENT(tt) (((tt) == PPTOK_IDENT) || ((tt) == PPTOK_IDENT_UNEXP)) +#define FIND(s, c) strchr(string_content((s)), (c)) +#define ONLYDIGS(s) (!FIND((s), '.') && !FIND((s), '+') && !FIND((s), '-')) + if (ISIDENT(tok1->tokt) && (ISIDENT(tok2->tokt) || ((tok2->tokt == PPTOK_NUM) && ONLYDIGS(tok2->tokv.str)))) { + tta_start = 1; --len; + tok1->tokt = PPTOK_IDENT; + if (!string_add_string(tok1->tokv.str, tok2->tokv.str)) { + LOG_MEMORY("failed to concatenate identifiers"); + vector_del(preproc, ret); + ret = NULL; + goto solve_done; + } + } else if ((tok1->tokt == PPTOK_NUM) && (ISIDENT(tok2->tokt) || (tok2->tokt == PPTOK_NUM))) { tta_start = 1; --len; - // TODO: check if concat is possible, what behaviour should be in the case below - if ((tok2->tokt == PPTOK_IDENT_UNEXP) && (tok1->tokt == PPTOK_IDENT)) tok1->tokt = PPTOK_IDENT; if (!string_add_string(tok1->tokv.str, tok2->tokv.str)) { - printf("Memory error while expanding %s\n", mname); + LOG_MEMORY("failed to concatenate identifiers"); vector_del(preproc, ret); ret = NULL; goto solve_done; } } else { - printf("Warning: unsupported concatenation between token type %u and %u while expanding %s\n", tok1->tokt, tok2->tokt, mname); + log_warning(li, "unsupported concatenation between token type %u and %u while expanding %s\n", tok1->tokt, tok2->tokt, mname); } +#undef ISIDENT +#undef FIND +#undef ONLYDIGS } if (len) { preproc_token_t tok2; @@ -595,33 +636,34 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char case PPTOK_NEWLINE: case PPTOK_BLANK: case PPTOK_START_LINE_COMMENT: - case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.c = tok1->tokv.c}; break; - case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.sym = tok1->tokv.sym}; break; + case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.c = tok1->tokv.c}; break; + case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sym = tok1->tokv.sym}; break; case PPTOK_IDENT: case PPTOK_IDENT_UNEXP: case PPTOK_NUM: { string_t *dup = string_dup(tok1->tokv.str); if (!dup) { - printf("Failed to duplicate string while expanding %s\n", mname); + LOG_MEMORY("failed to duplicate string"); vector_del(preproc, ret); ret = NULL; goto solve_done; } - tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.str = dup}; + tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.str = dup}; break; } case PPTOK_INCL: case PPTOK_STRING: { string_t *dup = string_dup(tok1->tokv.sstr); if (!dup) { - printf("Failed to duplicate string while expanding %s\n", mname); + LOG_MEMORY("failed to duplicate string"); vector_del(preproc, ret); ret = NULL; goto solve_done; } - tok2 = (preproc_token_t){.tokt = tok1->tokt, .tokv.sstr = dup, .tokv.sisstr = tok1->tokv.sisstr}; + tok2 = (preproc_token_t){.tokt = tok1->tokt, .loginfo = *li, .tokv.sstr = dup, .tokv.sisstr = tok1->tokv.sisstr}; break; } } if (!vector_push(preproc, ret, tok2)) { + LOG_MEMORY("failed to add token to output vector"); preproc_token_del(&tok2); vector_del(preproc, ret); ret = NULL; @@ -637,15 +679,15 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char break; } case MTOK_STRINGIFY: - // TODO: better stringifier if (concat_cur == 2) { - printf("Warning: unsupported concatenation with strings while expanding %s\n", mname); + log_warning(li, "invalid concatenation with string while expanding %s\n", mname); } + // TODO: better stringifier preproc_token_t tok2; { string_t *dup = string_new_cap(15); if (!dup) { - printf("Failed to duplicate string while expanding %s\n", mname); + LOG_MEMORY("failed to allocate stringify string"); vector_del(preproc, ret); ret = NULL; goto solve_done; @@ -665,9 +707,10 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char string_add_char(dup, 'r'); string_add_char(dup, 'g'); string_add_char(dup, '>'); - tok2 = (preproc_token_t){.tokt = PPTOK_STRING, .tokv.sstr = dup, .tokv.sisstr = 1}; + tok2 = (preproc_token_t){.tokt = PPTOK_STRING, .loginfo = *li, .tokv.sstr = dup, .tokv.sisstr = 1}; } if (!vector_push(preproc, ret, tok2)) { + LOG_MEMORY("failed to add token to output vector"); preproc_token_del(&tok2); vector_del(preproc, ret); ret = NULL; @@ -698,7 +741,7 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char int iret; kh_put(string_set, solved_macros, mname, &iret); if (iret < 0) { - printf("Memory error while expanding %s\n", mname); + LOG_MEMORY("failed to add current macro to the set of expanded macros"); vector_del(preproc, ret); free(mname); return NULL; @@ -706,7 +749,7 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char // Next expand every remaining macros vector_trim(preproc, ret); - VECTOR(preproc) *ret2 = proc_do_expand(macros, ret, solved_macros, opt_used_macros); + VECTOR(preproc) *ret2 = preproc_do_expand(li, macros, ret, solved_macros, opt_used_macros); vector_del(preproc, ret); ret = ret2; if (!ret) return NULL; // There was an error, abort @@ -714,7 +757,7 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char // Finally pop mname (in case we are expanding an argument) khiter_t it = kh_get(string_set, solved_macros, mname); if (it == kh_end(solved_macros)) { - printf("Unknown error while expanding a macro\n"); + log_internal(li, "failed to find current macro in the set of expanded macros while expanding %s\n" , mname); vector_del(preproc, ret); return NULL; } @@ -724,13 +767,17 @@ static VECTOR(preproc) *proc_solve_macro(const khash_t(macros_map) *macros, char #pragma GCC diagnostic pop kh_del(string_set, solved_macros, it); } +#undef LOG_MEMORY return ret; } -static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const VECTOR(preproc) *toks, - khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros) { +static VECTOR(preproc) *preproc_do_expand(loginfo_t *li, const khash_t(macros_map) *macros, const VECTOR(preproc) *toks, + khash_t(string_set) *solved_macros, khash_t(string_set) *opt_used_macros) { VECTOR(preproc) *toks2 = vector_new_cap(preproc, vector_size(preproc, toks)); - if (!toks2) return NULL; + if (!toks2) { + log_memory("failed to allocate full macro expansion auxiliary vector\n"); + return NULL; + } vector_for(preproc, tok, toks) { preproc_token_t tok2; switch (tok->tokt) { @@ -738,35 +785,38 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const case PPTOK_NEWLINE: case PPTOK_BLANK: case PPTOK_START_LINE_COMMENT: - case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok->tokt, .tokv.c = tok->tokv.c}; break; - case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok->tokt, .tokv.sym = tok->tokv.sym}; break; + case PPTOK_EOF: tok2 = (preproc_token_t){.tokt = tok->tokt, .loginfo = tok->loginfo, .tokv.c = tok->tokv.c}; break; + case PPTOK_SYM: tok2 = (preproc_token_t){.tokt = tok->tokt, .loginfo = tok->loginfo, .tokv.sym = tok->tokv.sym}; break; case PPTOK_IDENT: case PPTOK_IDENT_UNEXP: case PPTOK_NUM: { string_t *dup = string_dup(tok->tokv.str); if (!dup) { - printf("Failed to duplicate string during full macro expansion\n"); + log_memory("failed to duplicate string during full macro expansion\n"); vector_del(preproc, toks2); return NULL; } - tok2 = (preproc_token_t){.tokt = tok->tokt, .tokv.str = dup}; + tok2 = (preproc_token_t){.tokt = tok->tokt, .loginfo = tok->loginfo, .tokv.str = dup}; break; } case PPTOK_INCL: case PPTOK_STRING: { string_t *dup = string_dup(tok->tokv.sstr); if (!dup) { - printf("Failed to duplicate string during full macro expansion\n"); + log_memory("failed to duplicate string during full macro expansion\n"); vector_del(preproc, toks2); return NULL; } - tok2 = (preproc_token_t){.tokt = tok->tokt, .tokv.sstr = dup, .tokv.sisstr = tok->tokv.sisstr}; + tok2 = (preproc_token_t){.tokt = tok->tokt, .loginfo = tok->loginfo, .tokv.sstr = dup, .tokv.sisstr = tok->tokv.sisstr}; break; } } vector_push(preproc, toks2, tok2); // cap > size, thus this always succeed } VECTOR(preproc) *ret = vector_new_cap(preproc, vector_size(preproc, toks)); - if (!ret) return NULL; + if (!ret) { + log_memory("failed to allocate full macro expansion result vector\n"); + return NULL; + } vector_for(preproc, tok, toks2) { switch (tok->tokt) { case PPTOK_IDENT: { @@ -792,14 +842,14 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const char *mname2 = strdup(string_content(mname)); if (!mname2) { // Abort - printf("Failed to add %s to the list of used macros (strdup returned NULL)\n", string_content(mname)); + log_memory("failed to add %s to the list of used macros (strdup returned NULL)\n", string_content(mname)); goto expand_done; } kh_put(string_set, opt_used_macros, mname2, &iret); if (iret < 0) { // Abort free(mname2); - printf("Failed to add %s to the list of used macros (kh_put ireturned %d)\n", string_content(mname), iret); + log_memory("failed to add %s to the list of used macros (kh_put ireturned %d)\n", string_content(mname), iret); goto expand_done; } else if (iret == 0) { // Just free mname2, it was already present @@ -810,13 +860,13 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const string_t *num_str = string_new_cap(1); if (!num_str) { // Abort - printf("Failed to create defined() output\n"); + log_memory("failed to create defined() output\n"); goto expand_done; } khiter_t it = kh_get(macros_map, macros, string_content(mname)); string_add_char(num_str, (it == kh_end(macros)) ? '0' : '1'); - if (!vector_push(preproc, ret, ((preproc_token_t){.tokt = PPTOK_NUM, .tokv.str = num_str}))) { - printf("Failed to add defined() to the output\n"); + if (!vector_push(preproc, ret, ((preproc_token_t){.tokt = PPTOK_NUM, .loginfo = *li, .tokv.str = num_str}))) { + log_memory("failed to add defined() result to the output\n"); string_del(num_str); goto expand_done; } @@ -842,7 +892,7 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const unsigned depth = 1; VECTOR(preprocs) *margs = vector_new(preprocs); if (!margs) { - printf("Memory error (parsing macro use %s)\n", string_content(tok->tokv.str)); + log_memory("failed to allocate macro arguments for macro %s during full macro expansion\n", string_content(tok->tokv.str)); if (margs) vector_del(preprocs, margs); goto expand_done; } @@ -853,7 +903,7 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const ++tok2; if ((depth == 1) && (tok2->tokt == PPTOK_SYM) && (tok2->tokv.sym == SYM_COMMA)) { // Possible optimization: emplace NULL if vector_size(marg) == 0 - // This would avoid allocating a new vector, but needs support in proc_solve_macro + // This would avoid allocating a new vector, but needs support in preproc_solve_macro vector_trim(preproc, marg); if (!vector_push(preprocs, margs, marg)) goto gather_args_err_mem; marg = vector_new(preproc); @@ -878,7 +928,7 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const if (0) { gather_args_err_mem: - printf("Memory error (parsing macro use %s)\n", string_content(tok->tokv.str)); + log_memory("failed to gather macro arguments for macro %s during full macro expansion\n", string_content(tok->tokv.str)); if (marg) vector_del(preproc, marg); vector_del(preprocs, margs); goto expand_done; @@ -888,14 +938,14 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const char *mname = string_steal(tok->tokv.str); tok = tok2; - VECTOR(preproc) *expanded = proc_solve_macro(macros, mname, m, margs, solved_macros, opt_used_macros); + VECTOR(preproc) *expanded = preproc_solve_macro(li, macros, mname, m, margs, solved_macros, opt_used_macros); vector_del(preprocs, margs); if (!expanded) { // Error expanding the macro goto expand_done; } if (!vector_push_vec(preproc, ret, expanded)) { - printf("Memory error (pushing expanded macro to expanded macro)\n"); + log_memory("pushing expanded macro to full macro expansion\n"); vector_del(preproc, expanded); goto expand_done; } @@ -904,13 +954,13 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const break; } } else { - VECTOR(preproc) *expanded = proc_solve_macro(macros, string_steal(tok->tokv.str), m, NULL, solved_macros, opt_used_macros); + VECTOR(preproc) *expanded = preproc_solve_macro(li, macros, string_steal(tok->tokv.str), m, NULL, solved_macros, opt_used_macros); if (!expanded) { ++tok; // Current token is already freed (string stolen) goto expand_done; } if (!vector_push_vec(preproc, ret, expanded)) { - printf("Failed to extend output for full macro expansion\n"); + log_memory("failed to add macro expansion in output vector of full macro expansion\n"); ++tok; // Current token is already freed (string stolen) goto expand_done; } @@ -933,7 +983,7 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const case PPTOK_START_LINE_COMMENT: case PPTOK_EOF: if (!vector_push(preproc, ret, *tok)) { - printf("Failed to duplicate token during full macro expansion\n"); + log_memory("failed to add token to output vector during full macro expansion\n"); goto expand_done; } break; @@ -969,6 +1019,8 @@ static VECTOR(preproc) *proc_do_expand(const khash_t(macros_map) *macros, const #define OPLVL_AOR 9 // Bitwise (Arithmetic) #define OPLVL_BAN 10 // Boolean #define OPLVL_BOR 11 // Boolean +#define OPLVL_ALL 12 // Evaluate the entire stack +#define OPLVL_ALS 13 // Evaluate the entire stack, (don't update the states (ignored)) #define OPTYP_MUL 1 #define OPTYP_DIV 2 #define OPTYP_MOD 3 @@ -1003,22 +1055,242 @@ typedef struct preproc_eval_aux_s { int64_t v0; unsigned st1; const preproc_token_t *v1; - int64_t v2; - int64_t v3; - int64_t v4; - int64_t v5; - int64_t v6; - int64_t v7; - int64_t v8; - int64_t v9; + int64_t v2; loginfo_t li2; + int64_t v3; loginfo_t li3; + int64_t v4; loginfo_t li4; + int64_t v5; loginfo_t li5; + int64_t v6; loginfo_t li6; + int64_t v7; loginfo_t li7; + int64_t v8; loginfo_t li8; + int64_t v9; loginfo_t li9; + loginfo_t libool; unsigned n_colons; // Number of ':' expected (needs to skip to the end), ie number of ternary where the truth-y branch is taken } preproc_eval_aux_t; VECTOR_DECLARE_STATIC(ppeaux, preproc_eval_aux_t) VECTOR_IMPL_STATIC(ppeaux, (void)) +static int64_t eval_stack(preproc_eval_aux_t *st, loginfo_t li, int max_lv, int optype, _Bool is_unsigned, int *success) { + if (!li.lineno_end) { + li.lineno_end = li.lineno; + li.colno_end = li.colno; + } + + int64_t acc = st->v0; + st->st0 = 0; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wduplicated-cond" // For the else if (st->stX) + if (st->st2 == OPTYP_MUL) { + acc = st->v2 * acc; + st->st2 = 0; + li.lineno = st->li2.lineno; + li.colno = st->li2.colno; + } else if (st->st2 == OPTYP_DIV) { + if (!acc) { + log_error(&li, "division by zero during #if evaluation\n"); + *success = 0; + return 0; + } + acc = st->v2 / acc; + st->st2 = 0; + li.lineno = st->li2.lineno; + li.colno = st->li2.colno; + } else if (st->st2 == OPTYP_MOD) { + if (!acc) { + log_error(&li, "division by zero during #if evaluation\n"); + *success = 0; + return 0; + } + acc = st->v2 % acc; + st->st2 = 0; + li.lineno = st->li2.lineno; + li.colno = st->li2.colno; + } else if (st->st2) { + log_internal(&st->li2, "unknown st2 %d during #if evaluation\n", st->st2); + *success = 0; + return 0; + } + if (max_lv == 2) { + st->st2 = optype; + st->v2 = acc; + st->li2 = li; + return acc; + } + if (st->st3 == OPTYP_ADD) { + acc = st->v3 + acc; + st->st3 = 0; + li.lineno = st->li3.lineno; + li.colno = st->li3.colno; + } else if (st->st3 == OPTYP_SUB) { + acc = st->v3 - acc; + st->st3 = 0; + li.lineno = st->li3.lineno; + li.colno = st->li3.colno; + } else if (st->st3) { + log_internal(&st->li3, "unknown st3 %d during #if evaluation\n", st->st3); + *success = 0; + return 0; + } + if (max_lv == 3) { + st->st3 = optype; + st->v3 = acc; + st->li3 = li; + return acc; + } + if (st->st4 == OPTYP_LSL) { + acc = st->v4 << acc; + st->st4 = 0; + li.lineno = st->li4.lineno; + li.colno = st->li4.colno; + } else if (st->st4 == OPTYP_LSR) { + acc = is_unsigned ? (int64_t)((uint64_t)st->v4 >> (uint64_t)acc) : (st->v4 >> acc); + st->st4 = 0; + li.lineno = st->li4.lineno; + li.colno = st->li4.colno; + } else if (st->st4) { + log_internal(&st->li4, "unknown st4 %d during #if evaluation\n", st->st4); + *success = 0; + return 0; + } + if (max_lv == 4) { + st->st4 = optype; + st->v4 = acc; + st->li4 = li; + return acc; + } + if (st->st5 == OPTYP_LET) { + acc = is_unsigned ? ((uint64_t)st->v5 < (uint64_t)acc) : (st->v5 < acc); + is_unsigned = 0; + st->st5 = 0; + li.lineno = st->li5.lineno; + li.colno = st->li5.colno; + } else if (st->st5 == OPTYP_LEE) { + acc = is_unsigned ? ((uint64_t)st->v5 <= (uint64_t)acc) : (st->v5 <= acc); + is_unsigned = 0; + st->st5 = 0; + li.lineno = st->li5.lineno; + li.colno = st->li5.colno; + } else if (st->st5 == OPTYP_GRT) { + acc = is_unsigned ? ((uint64_t)st->v5 > (uint64_t)acc) : (st->v5 > acc); + is_unsigned = 0; + st->st5 = 0; + li.lineno = st->li5.lineno; + li.colno = st->li5.colno; + } else if (st->st5 == OPTYP_GRE) { + acc = is_unsigned ? ((uint64_t)st->v5 >= (uint64_t)acc) : (st->v5 >= acc); + is_unsigned = 0; + st->st5 = 0; + li.lineno = st->li5.lineno; + li.colno = st->li5.colno; + } else if (st->st5) { + log_internal(&st->li5, "unknown st5 %d during #if evaluation\n", st->st5); + *success = 0; + return 0; + } + if (max_lv == 5) { + st->st5 = optype; + st->v5 = acc; + st->li5 = li; + return acc; + } + if (st->st6 == OPTYP_EQU) { + acc = st->v6 == acc; + st->st6 = 0; + li.lineno = st->li6.lineno; + li.colno = st->li6.colno; + } else if (st->st6 == OPTYP_NEQ) { + acc = st->v6 != acc; + st->st6 = 0; + li.lineno = st->li6.lineno; + li.colno = st->li6.colno; + } else if (st->st6) { + log_internal(&st->li6, "unknown st6 %d during #if evaluation\n", st->st6); + *success = 0; + return 0; + } + if (max_lv == 6) { + st->st6 = optype; + st->v6 = acc; + st->li6 = li; + return acc; + } + if (st->st7 == OPTYP_AAN) { + acc = st->v7 & acc; + st->st7 = 0; + li.lineno = st->li7.lineno; + li.colno = st->li7.colno; + } else if (st->st7) { + log_internal(&st->li7, "unknown st7 %d during #if evaluation\n", st->st7); + *success = 0; + return 0; + } + if (max_lv == 7) { + st->st7 = optype; + st->v7 = acc; + st->li7 = li; + return acc; + } + if (st->st8 == OPTYP_XOR) { + acc = st->v8 ^ acc; + st->st8 = 0; + li.lineno = st->li8.lineno; + li.colno = st->li8.colno; + } else if (st->st8) { + log_internal(&st->li8, "unknown st8 %d during #if evaluation\n", st->st8); + *success = 0; + return 0; + } + if (max_lv == 8) { + st->st8 = optype; + st->v8 = acc; + st->li8 = li; + return acc; + } + if (st->st9 == OPTYP_AOR) { + acc = st->v9 | acc; + st->st9 = 0; + li.lineno = st->li9.lineno; + li.colno = st->li9.colno; + } else if (st->st9) { + log_internal(&st->li9, "unknown st9 %d during #if evaluation\n", st->st9); + *success = 0; + return 0; + } + if (max_lv == 9) { + st->st9 = optype; + st->v9 = acc; + st->li9 = li; + return acc; + } + if (max_lv == 10) { // OPLVL == OPLVL_BAN, OPTYP == OPTYP_BAN + li.lineno = st->libool.lineno; + li.colno = st->libool.colno; + st->libool = li; + return acc; + } + if (max_lv == 11) { // OPLVL == OPLVL_BOR, OPTYP == OPTYP_BOR + li.lineno = st->libool.lineno; + li.colno = st->libool.colno; + st->libool = li; + return acc; + } + if (st->st_bool) { + acc = !!acc; + st->st_bool = 0; + } + if ((max_lv == OPLVL_ALL) || (max_lv == OPLVL_ALS)) { + return acc; + } +#pragma GCC diagnostic pop + log_internal(&li, "invalid max level %d in preprocessor partial expression evaluation\n", max_lv); + *success = 0; + return acc; +} static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_is_32bits) { + int success; VECTOR(ppeaux) *stack = vector_new_cap(ppeaux, 1); if (!stack) { - printf("Failed to allocate #if evaluation stack vector\n"); + log_memory("failed to allocate #if evaluation stack vector\n"); *aux_ret = 0; return 0; } @@ -1029,13 +1301,13 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i return 0; } vector_push(ppeaux, stack, (preproc_eval_aux_t){0}); // vector_cap >= 1 - int64_t acc; _Bool is_unsigned = 0; + int64_t acc; loginfo_t li0; _Bool is_unsigned = 0; vector_for(preproc, tok, cond) { if (tok->tokt == PPTOK_NUM) { // Evaluate token as an integer if st0 == 0, error otherwise if (vector_last(ppeaux, stack).st0 == 0) { num_constant_t cst; - if (!num_constant_convert(tok->tokv.str, &cst, ptr_is_32bits)) { + if (!num_constant_convert(&tok->loginfo, tok->tokv.str, &cst, ptr_is_32bits)) { goto eval_fail; } switch (cst.typ) { @@ -1047,21 +1319,23 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i case NCT_DOUBLE: case NCT_LDOUBLE: default: - printf("Number '%s' is not a valid integer (during #if evaluation)\n", string_content(tok->tokv.str)); + log_error(&tok->loginfo, "number '%s' is not a valid integer (during #if evaluation)\n", string_content(tok->tokv.str)); goto eval_fail; } + li0 = tok->loginfo; goto push_acc_to_st0; } else { - printf("Invalid number during #if evaluation\n"); + log_error(&tok->loginfo, "unexpected number during #if evaluation\n"); goto eval_fail; } } else if ((tok->tokt == PPTOK_IDENT) || (tok->tokt == PPTOK_IDENT_UNEXP)) { // Evaluate token as 0 if st0 == 0, error otherwise if (vector_last(ppeaux, stack).st0 == 0) { acc = 0; + li0 = tok->loginfo; goto push_acc_to_st0; } else { - printf("Invalid ident '%s' during #if evaluation\n", string_content(tok->tokv.str)); + log_error(&tok->loginfo, "unexpected ident '%s' during #if evaluation\n", string_content(tok->tokv.str)); goto eval_fail; } } else if (tok->tokt == PPTOK_SYM) { @@ -1070,30 +1344,26 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i switch (tok->tokv.sym) { case SYM_TILDE: // Unary (st0 == 0) - if (vector_last(ppeaux, stack).st0 == 0) { - // Unary, prepare lv1 then continue to the next token - if (!(vector_last(ppeaux, stack).st1++)) { - // Also update v1, since this is the first level 1 operator - vector_last(ppeaux, stack).v1 = tok; - } - goto done_partial_eval; - } else { - printf("Invalid %snary '%s' in #if expression\n", "u", sym2str[tok->tokv.sym]); + if (vector_last(ppeaux, stack).st0 != 0) { + log_error(&tok->loginfo, "unexpected unary '~' in #if expression\n"); goto eval_fail; } + if (!(vector_last(ppeaux, stack).st1++)) { + // Also update v1, since this is the first level 1 operator + vector_last(ppeaux, stack).v1 = tok; + } + goto done_partial_eval; case SYM_EXCL: // Unary (st0 == 0) - if (vector_last(ppeaux, stack).st0 == 0) { - // Unary, prepare lv1 then continue to the next token - if (!(vector_last(ppeaux, stack).st1++)) { - // Also update v1, since this is the first level 1 operator - vector_last(ppeaux, stack).v1 = tok; - } - goto done_partial_eval; - } else { - printf("Invalid %snary '%s' in #if expression\n", "u", sym2str[tok->tokv.sym]); + if (vector_last(ppeaux, stack).st0 != 0) { + log_error(&tok->loginfo, "unexpected unary '!' in #if expression\n"); goto eval_fail; } + if (!(vector_last(ppeaux, stack).st1++)) { + // Also update v1, since this is the first level 1 operator + vector_last(ppeaux, stack).v1 = tok; + } + goto done_partial_eval; case SYM_PLUS: // May be unary (st0 == 0) or binary (st0 != 0) if (vector_last(ppeaux, stack).st0 == 0) { @@ -1106,7 +1376,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i } else { op_lvl = OPLVL_ADD; op_typ = OPTYP_ADD; - break; + goto add_binop; } case SYM_DASH: // May be unary (st0 == 0) or binary (st0 != 0) @@ -1120,363 +1390,222 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i } else { op_lvl = OPLVL_SUB; op_typ = OPTYP_SUB; - break; + goto add_binop; } case SYM_STAR: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_MUL; - op_typ = OPTYP_MUL; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_MUL; + op_typ = OPTYP_MUL; + goto add_binop; case SYM_SLASH: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_DIV; - op_typ = OPTYP_DIV; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_DIV; + op_typ = OPTYP_DIV; + goto add_binop; case SYM_PERCENT: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_MOD; - op_typ = OPTYP_MOD; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_MOD; + op_typ = OPTYP_MOD; + goto add_binop; case SYM_HAT: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_XOR; - op_typ = OPTYP_XOR; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_XOR; + op_typ = OPTYP_XOR; + goto add_binop; case SYM_AMP: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_AAN; - op_typ = OPTYP_AAN; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_AAN; + op_typ = OPTYP_AAN; + goto add_binop; case SYM_PIPE: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_AOR; - op_typ = OPTYP_AOR; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_AOR; + op_typ = OPTYP_AOR; + goto add_binop; case SYM_EQEQ: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_EQU; - op_typ = OPTYP_EQU; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_EQU; + op_typ = OPTYP_EQU; + goto add_binop; case SYM_EXCLEQ: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_NEQ; - op_typ = OPTYP_NEQ; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_NEQ; + op_typ = OPTYP_NEQ; + goto add_binop; case SYM_LT: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_LET; - op_typ = OPTYP_LET; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_LET; + op_typ = OPTYP_LET; + goto add_binop; case SYM_GT: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_GRT; - op_typ = OPTYP_GRT; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_GRT; + op_typ = OPTYP_GRT; + goto add_binop; case SYM_LTEQ: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_LEE; - op_typ = OPTYP_LEE; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_LEE; + op_typ = OPTYP_LEE; + goto add_binop; case SYM_GTEQ: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_GRE; - op_typ = OPTYP_GRE; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_GRE; + op_typ = OPTYP_GRE; + goto add_binop; case SYM_AMPAMP: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_BAN; - op_typ = OPTYP_BAN; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_BAN; + op_typ = OPTYP_BAN; + goto add_binop; case SYM_PIPEPIPE: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_BOR; - op_typ = OPTYP_BOR; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_BOR; + op_typ = OPTYP_BOR; + goto add_binop; case SYM_LTLT: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_LSL; - op_typ = OPTYP_LSL; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_LSL; + op_typ = OPTYP_LSL; + goto add_binop; case SYM_GTGT: // Binary (st0 != 0) - if (vector_last(ppeaux, stack).st0 == 0) { - printf("Invalid %snary '%s' in #if expression\n", "bi", sym2str[tok->tokv.sym]); - goto eval_fail; - } else { - op_lvl = OPLVL_LSR; - op_typ = OPTYP_LSR; - break; - } + if (vector_last(ppeaux, stack).st0 == 0) goto invalid_binop; + op_lvl = OPLVL_LSR; + op_typ = OPTYP_LSR; + goto add_binop; case SYM_LPAREN: // May be placed anywhere a constant is expected (st0 == 0) and simply pushes a new stack - if (vector_last(ppeaux, stack).st0 == 0) { - if (!vector_push(ppeaux, stack, (preproc_eval_aux_t){0})) { - printf("Failed to push to the stack during #if evaluation\n"); - goto eval_fail; - } - goto done_partial_eval; - } else { - printf("Invalid opening parenthesis in #if expression\n"); - goto eval_fail; - } - case SYM_RPAREN: - case SYM_QUESTION: - // May be placed anywhere and simply pushes a new stack (paren) or more complex operation (ternary) - if ((tok->tokv.sym == SYM_RPAREN) && (vector_size(ppeaux, stack) == 1)) { - printf("Invalid closing parenthesis during #if evaluation\n"); - goto eval_fail; - } - if (!vector_last(ppeaux, stack).st0) { - printf("Invalid %s during #if evaluation\n", (tok->tokv.sym == SYM_RPAREN) ? "closing parenthesis" : "question mark"); - goto eval_fail; - } - - // Evaluate the top of the stack, then pop - acc = vector_last(ppeaux, stack).v0; - vector_last(ppeaux, stack).st0 = 0; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wduplicated-cond" // For the else if (.stX) - if (vector_last(ppeaux, stack).st2 == OPTYP_MUL) { - acc = vector_last(ppeaux, stack).v2 * acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2 == OPTYP_DIV) { - if (!acc) { - printf("Error: division by zero\n"); - goto eval_fail; - } - acc = vector_last(ppeaux, stack).v2 / acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2 == OPTYP_MOD) { - if (!acc) { - printf("Error: division by zero\n"); - goto eval_fail; - } - acc = vector_last(ppeaux, stack).v2 % acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2) { - printf(" Unknown st2 %d during #if evaluation\n", vector_last(ppeaux, stack).st2); + if (vector_last(ppeaux, stack).st0 != 0) { + log_error(&tok->loginfo, "unexpected opening parenthesis in #if expression\n"); goto eval_fail; } - if (vector_last(ppeaux, stack).st3 == OPTYP_ADD) { - acc = vector_last(ppeaux, stack).v3 + acc; - vector_last(ppeaux, stack).st3 = 0; - } else if (vector_last(ppeaux, stack).st3 == OPTYP_SUB) { - acc = vector_last(ppeaux, stack).v3 - acc; - vector_last(ppeaux, stack).st3 = 0; - } else if (vector_last(ppeaux, stack).st3) { - printf(" Unknown st3 %d during #if evaluation\n", vector_last(ppeaux, stack).st3); + if (!vector_push(ppeaux, stack, (preproc_eval_aux_t){0})) { + log_memory("failed to push a new stack during #if evaluation\n"); goto eval_fail; } - if (vector_last(ppeaux, stack).st4 == OPTYP_LSL) { - acc = vector_last(ppeaux, stack).v4 << acc; - vector_last(ppeaux, stack).st4 = 0; - } else if (vector_last(ppeaux, stack).st4 == OPTYP_LSR) { - acc = is_unsigned ? (int64_t)((uint64_t)vector_last(ppeaux, stack).v4 >> (uint64_t)acc) : (vector_last(ppeaux, stack).v4 >> acc); - vector_last(ppeaux, stack).st4 = 0; - } else if (vector_last(ppeaux, stack).st4) { - printf(" Unknown st4 %d during #if evaluation\n", vector_last(ppeaux, stack).st4); + goto done_partial_eval; + case SYM_RPAREN: + // May be placed anywhere after a constant (st0 != 0) + if (vector_size(ppeaux, stack) == 1) { + log_error(&tok->loginfo, "unexpected symbol ')' (parenthesis not opened) during #if evaluation\n"); goto eval_fail; } - if (vector_last(ppeaux, stack).st5 == OPTYP_LET) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 < (uint64_t)acc) : (vector_last(ppeaux, stack).v5 < acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_LEE) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 <= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 <= acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_GRT) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 > (uint64_t)acc) : (vector_last(ppeaux, stack).v5 > acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_GRE) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 >= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 >= acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5) { - printf(" Unknown st5 %d during #if evaluation\n", vector_last(ppeaux, stack).st5); + if (vector_last(ppeaux, stack).n_colons) { + log_error(&tok->loginfo, "unexpected symbol ')', expected symbol ':' during #if evaluation\n"); goto eval_fail; } - if (vector_last(ppeaux, stack).st6 == OPTYP_EQU) { - acc = vector_last(ppeaux, stack).v6 == acc; - vector_last(ppeaux, stack).st6 = 0; - } else if (vector_last(ppeaux, stack).st6 == OPTYP_NEQ) { - acc = vector_last(ppeaux, stack).v6 != acc; - vector_last(ppeaux, stack).st6 = 0; - } else if (vector_last(ppeaux, stack).st6) { - printf(" Unknown st6 %d during #if evaluation\n", vector_last(ppeaux, stack).st6); + if (!vector_last(ppeaux, stack).st0) { + log_error(&tok->loginfo, "unexpected symbol ')' during #if evaluation\n"); goto eval_fail; } - if (vector_last(ppeaux, stack).st7 == OPTYP_AAN) { - acc = vector_last(ppeaux, stack).v7 & acc; - vector_last(ppeaux, stack).st7 = 0; - } else if (vector_last(ppeaux, stack).st7) { - printf(" Unknown st7 %d during #if evaluation\n", vector_last(ppeaux, stack).st7); + + eval_rparen: + // Evaluate the top of the stack, then pop + success = 1; + acc = eval_stack(&vector_last(ppeaux, stack), li0, OPLVL_ALS, 0, is_unsigned, &success); + if (!success) { goto eval_fail; } - if (vector_last(ppeaux, stack).st8 == OPTYP_XOR) { - acc = vector_last(ppeaux, stack).v8 ^ acc; - vector_last(ppeaux, stack).st8 = 0; - } else if (vector_last(ppeaux, stack).st8) { - printf(" Unknown st8 %d during #if evaluation\n", vector_last(ppeaux, stack).st8); + + eval_rparen_acc: + vector_pop(ppeaux, stack); + goto push_acc_to_st0; + + case SYM_QUESTION: { + // May be placed anywhere and may skip some tokens depending on acc + if (!vector_last(ppeaux, stack).st0) { + log_error(&tok->loginfo, "unexpected ternary operator during #if evaluation\n"); goto eval_fail; } - if (vector_last(ppeaux, stack).st9 == OPTYP_AOR) { - acc = vector_last(ppeaux, stack).v9 | acc; - vector_last(ppeaux, stack).st9 = 0; - } else if (vector_last(ppeaux, stack).st9) { - printf(" Unknown st9 %d during #if evaluation\n", vector_last(ppeaux, stack).st9); + + // Evaluate the top of the stack, then increase n_colons or skip tokens + success = 1; + acc = eval_stack(&vector_last(ppeaux, stack), li0, OPLVL_ALL, 0, is_unsigned, &success); + if (!success) { goto eval_fail; } - if (vector_last(ppeaux, stack).st_bool) { - acc = !!acc; - vector_last(ppeaux, stack).st_bool = 0; - } -#pragma GCC diagnostic pop - if (tok->tokv.sym == SYM_RPAREN) { - vector_pop(ppeaux, stack); - goto push_acc_to_st0; + eval_question_acc: + is_unsigned = 0; + if (acc) { + // Increase n_colons + ++vector_last(ppeaux, stack).n_colons; + goto done_partial_eval; } else { - eval_question_acc: - is_unsigned = 0; - if (acc) { - // Increase n_colons - ++vector_last(ppeaux, stack).n_colons; - goto done_partial_eval; - } else { - // Skip to the corresponding colon - unsigned nquestions = 0, nparens = 0; - // Note that we don't really care about the content of the ignored part; it may be syntaxically incorrect - for (++tok; tok < vector_end(preproc, cond); ++tok) { - if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { - ++nparens; - } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { - if (nparens) --nparens; - else { - printf("Unclosed parenthesis in #if evaluation\n"); - goto eval_fail; - } - } else if (!nparens && (tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) { - ++nquestions; - } else if (!nparens && (tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_COLON)) { - if (nquestions) --nquestions; - else break; - } - } - if (tok == vector_end(preproc, cond)) { - printf("Unfinished ternary operator in #if evaluation\n"); - goto eval_fail; - } - goto done_partial_eval; - } - } - case SYM_COLON: - if (vector_last(ppeaux, stack).n_colons) { - // Decrease n_colons and skip to the rparen/end of vector - if (vector_size(ppeaux, stack) == 1) { - goto done_complete_stack; // No rparen, skip to the end of the vector - } - // Skip to the next rparen; also, we skip the correct count of ':' since we don't care about those anymore - // --vector_last(ppeaux, stack).n_colons; - unsigned nparens = 0; + // Skip to the corresponding colon + unsigned nquestions = 0, nparens = 0; // Note that we don't really care about the content of the ignored part; it may be syntaxically incorrect for (++tok; tok < vector_end(preproc, cond); ++tok) { if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { ++nparens; } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { if (nparens) --nparens; + else { + log_error(&tok->loginfo, "unexpected symbol ')', expected ':' during #if evaluation\n"); + goto eval_fail; + } + } else if (!nparens && (tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) { + ++nquestions; + } else if (!nparens && (tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_COLON)) { + if (nquestions) --nquestions; else break; } } if (tok == vector_end(preproc, cond)) { - printf("Unfinished ternary operator in #if evaluation\n"); + log_error(&tok->loginfo, "ternary operator never finished during #if evaluation\n"); goto eval_fail; } - --tok; goto done_partial_eval; - } else { - printf("Invalid colon symbol during #if evaluation\n"); + } + } + case SYM_COLON: { + if (!vector_last(ppeaux, stack).n_colons) { + log_error(&tok->loginfo, "unexpected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + if (!vector_last(ppeaux, stack).st0) { + log_error(&tok->loginfo, "unexpected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + eval_colon_acc: + // Skip to the end of expression or to the corresponding rparen + if (vector_size(ppeaux, stack) == 1) { + goto done_complete_stack; // No parenthesis opened, skip to the end of the vector + } + // Skip to the next rparen; also, we skip correctly counting of ':' since we don't care about those anymore + unsigned nparens = 0; + // Note that we don't really care about the content of the ignored part; it may be syntaxically incorrect + for (++tok; tok < vector_end(preproc, cond); ++tok) { + if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { + ++nparens; + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { + if (nparens) --nparens; + else break; + } + } + // We need to exit at a RPAREN + if (tok == vector_end(preproc, cond)) { + log_error(&vector_last(preproc, cond).loginfo, "missing closing parenthesis in #if expression\n"); goto eval_fail; } + vector_last(ppeaux, stack).n_colons = 0; + goto eval_rparen; } case SYM_LBRACKET: case SYM_RBRACKET: @@ -1504,228 +1633,165 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i case SYM_DASHDASH: case SYM_COMMA: default: - printf("Invalid symbol ID %u during #if evaluation\n", tok->tokv.sym); + log_error(&tok->loginfo, "invalid symbol ID %u (%s) during #if evaluation\n", + tok->tokv.sym, (tok->tokv.sym <= LAST_SYM) ? sym2str[tok->tokv.sym] : "invalid"); goto eval_fail; } - acc = vector_last(ppeaux, stack).v0; - vector_last(ppeaux, stack).st0 = 0; - if (op_lvl < 2) { - printf(" Invalid op_lvl %d < 2 during #if evaluation\n", op_lvl); + // invalid_binop: unexpected binary operation + // add_binop: add a binary operation + if (0) { + invalid_binop: + log_error(&tok->loginfo, "unexpected binary operator '%s' in #if expression\n", sym2str[tok->tokv.sym]); goto eval_fail; - } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wduplicated-cond" // For the else if (.stX) - if (vector_last(ppeaux, stack).st2 == OPTYP_MUL) { - acc = vector_last(ppeaux, stack).v2 * acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2 == OPTYP_DIV) { - if (!acc) { - printf("Error: division by zero\n"); + add_binop: + if (op_lvl < 2) { + log_internal(&tok->loginfo, "invalid op_lvl %d < 2 during #if evaluation\n", op_lvl); goto eval_fail; } - acc = vector_last(ppeaux, stack).v2 / acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2 == OPTYP_MOD) { - if (!acc) { - printf("Error: division by zero\n"); + if (op_lvl >= OPLVL_ALL) { + log_internal(&tok->loginfo, "invalid op_lvl %d > OPLVL_ALL during #if evaluation\n", op_lvl); goto eval_fail; } - acc = vector_last(ppeaux, stack).v2 % acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2) { - printf(" Unknown st2 %d during #if evaluation\n", vector_last(ppeaux, stack).st2); - goto eval_fail; - } - if (op_lvl == 2) { - vector_last(ppeaux, stack).st2 = op_typ; - vector_last(ppeaux, stack).v2 = acc; - goto done_partial_eval; - } - if (vector_last(ppeaux, stack).st3 == OPTYP_ADD) { - acc = vector_last(ppeaux, stack).v3 + acc; - vector_last(ppeaux, stack).st3 = 0; - } else if (vector_last(ppeaux, stack).st3 == OPTYP_SUB) { - acc = vector_last(ppeaux, stack).v3 - acc; - vector_last(ppeaux, stack).st3 = 0; - } else if (vector_last(ppeaux, stack).st3) { - printf(" Unknown st3 %d during #if evaluation\n", vector_last(ppeaux, stack).st3); - goto eval_fail; - } - if (op_lvl == 3) { - vector_last(ppeaux, stack).st3 = op_typ; - vector_last(ppeaux, stack).v3 = acc; - goto done_partial_eval; - } - if (vector_last(ppeaux, stack).st4 == OPTYP_LSL) { - acc = vector_last(ppeaux, stack).v4 << acc; - vector_last(ppeaux, stack).st4 = 0; - } else if (vector_last(ppeaux, stack).st4 == OPTYP_LSR) { - acc = is_unsigned ? (int64_t)((uint64_t)vector_last(ppeaux, stack).v4 >> (uint64_t)acc) : (vector_last(ppeaux, stack).v4 >> acc); - vector_last(ppeaux, stack).st4 = 0; - } else if (vector_last(ppeaux, stack).st4) { - printf(" Unknown st4 %d during #if evaluation\n", vector_last(ppeaux, stack).st4); - goto eval_fail; - } - if (op_lvl == 4) { - vector_last(ppeaux, stack).st4 = op_typ; - vector_last(ppeaux, stack).v4 = acc; - goto done_partial_eval; - } - if (vector_last(ppeaux, stack).st5 == OPTYP_LET) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 < (uint64_t)acc) : (vector_last(ppeaux, stack).v5 < acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_LEE) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 <= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 <= acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_GRT) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 > (uint64_t)acc) : (vector_last(ppeaux, stack).v5 > acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_GRE) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 >= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 >= acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5) { - printf(" Unknown st5 %d during #if evaluation\n", vector_last(ppeaux, stack).st5); - goto eval_fail; - } - if (op_lvl == 5) { - vector_last(ppeaux, stack).st5 = op_typ; - vector_last(ppeaux, stack).v5 = acc; - goto done_partial_eval; - } - if (vector_last(ppeaux, stack).st6 == OPTYP_EQU) { - acc = vector_last(ppeaux, stack).v6 == acc; - vector_last(ppeaux, stack).st6 = 0; - } else if (vector_last(ppeaux, stack).st6 == OPTYP_NEQ) { - acc = vector_last(ppeaux, stack).v6 != acc; - vector_last(ppeaux, stack).st6 = 0; - } else if (vector_last(ppeaux, stack).st6) { - printf(" Unknown st6 %d during #if evaluation\n", vector_last(ppeaux, stack).st6); - goto eval_fail; - } - if (op_lvl == 6) { - vector_last(ppeaux, stack).st6 = op_typ; - vector_last(ppeaux, stack).v6 = acc; - goto done_partial_eval; - } - if (vector_last(ppeaux, stack).st7 == OPTYP_AAN) { - acc = vector_last(ppeaux, stack).v7 & acc; - vector_last(ppeaux, stack).st7 = 0; - } else if (vector_last(ppeaux, stack).st7) { - printf(" Unknown st7 %d during #if evaluation\n", vector_last(ppeaux, stack).st7); - goto eval_fail; - } - if (op_lvl == 7) { - vector_last(ppeaux, stack).st7 = op_typ; - vector_last(ppeaux, stack).v7 = acc; - goto done_partial_eval; - } - if (vector_last(ppeaux, stack).st8 == OPTYP_XOR) { - acc = vector_last(ppeaux, stack).v8 ^ acc; - vector_last(ppeaux, stack).st8 = 0; - } else if (vector_last(ppeaux, stack).st8) { - printf(" Unknown st8 %d during #if evaluation\n", vector_last(ppeaux, stack).st8); - goto eval_fail; - } - if (op_lvl == 8) { - vector_last(ppeaux, stack).st8 = op_typ; - vector_last(ppeaux, stack).v8 = acc; - goto done_partial_eval; - } - if (vector_last(ppeaux, stack).st9 == OPTYP_AOR) { - acc = vector_last(ppeaux, stack).v9 | acc; - vector_last(ppeaux, stack).st9 = 0; - } else if (vector_last(ppeaux, stack).st9) { - printf(" Unknown st9 %d during #if evaluation\n", vector_last(ppeaux, stack).st9); - goto eval_fail; - } - if (op_lvl == 9) { - vector_last(ppeaux, stack).st9 = op_typ; - vector_last(ppeaux, stack).v9 = acc; - goto done_partial_eval; - } - if (op_lvl == 10) { - // We know that sym == SYM_AMPAMP, so we need to skip evaluating the remainder if it equals 0 - if (acc) goto done_partial_eval; - is_unsigned = 0; - unsigned nparens = 0; - // 0 && y ? z : w => w - // 0 && y || z => z - // Otherwise, keep skipping to the next token - for (++tok; tok < vector_end(preproc, cond); ++tok) { - if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { - ++nparens; - } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { - if (nparens) --nparens; - else { - vector_last(ppeaux, stack).v0 = acc; - vector_last(ppeaux, stack).st0 = 1; - --tok; - goto done_partial_eval; + + success = 1; + acc = eval_stack(&vector_last(ppeaux, stack), li0, op_lvl, op_typ, is_unsigned, &success); + if (!success) { + goto eval_fail; + } + + if (op_lvl < OPLVL_BAN) { + // No post-processing required + goto done_partial_eval; + } + if (op_lvl == OPLVL_BAN) { + // op_typ == OPLVL_BAN + vector_last(ppeaux, stack).st_bool = 1; + if (acc) goto done_partial_eval; + // We have five possibilities: + // [0] && x ~> 0 + // [0] && x) ~> 0) + // [0] && x ? y : z ~> z + // [0] && x : y ~> 0 : y ~> 0 + // [0] && x || y ~> y + // We are at the '&&'; note that we know the top of the stack has no pending operation + unsigned nparens = 0; + for (++tok; tok < vector_end(preproc, cond); ++tok) { + if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { + ++nparens; + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { + if (nparens) --nparens; + else { + if (vector_size(ppeaux, stack) == 1) { + log_error(&tok->loginfo, "unexpected symbol ')' (parenthesis not opened) during #if evaluation\n"); + goto eval_fail; + } + if (vector_last(ppeaux, stack).n_colons) { + log_error(&tok->loginfo, "unexpected symbol ')', expected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + + goto eval_rparen_acc; + } + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) { + if (!nparens) { + goto eval_question_acc; + } + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_COLON)) { + if (!nparens) { + if (!vector_last(ppeaux, stack).n_colons) { + log_error(&tok->loginfo, "unexpected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + goto eval_colon_acc; + } + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_PIPEPIPE)) { + if (!nparens) { + goto done_partial_eval; + } } - } else if (!nparens && (tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) { - goto eval_question_acc; - } else if (!nparens && (tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_PIPEPIPE)) { - break; } - } - if (tok == vector_end(preproc, cond)) { - if (!nparens) goto done_complete_acc; - else { - printf("Unclosed parenthesis in #if evaluation\n"); + if (nparens) { + log_error(&vector_last(preproc, cond).loginfo, "expected symbol ')' during #if evaluation\n"); goto eval_fail; } - } - goto done_partial_eval; - } - if (op_lvl == 11) { - // We know that sym == SYM_PIPEPIPE, so we need to skip evaluating the remainder if it equals 1 - if (!acc) goto done_partial_eval; - is_unsigned = 0; - unsigned nparens = 0; - // 0 || y ? z : w => w - // Otherwise, keep skipping to the next token - for (++tok; tok < vector_end(preproc, cond); ++tok) { - if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { - ++nparens; - } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { - if (nparens) --nparens; - else { - vector_last(ppeaux, stack).v0 = acc; - vector_last(ppeaux, stack).st0 = 1; - --tok; - goto done_partial_eval; + if (vector_last(ppeaux, stack).n_colons) { + log_error(&vector_last(preproc, cond).loginfo, "expected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + if (vector_size(ppeaux, stack) != 1) { + log_error(&vector_last(preproc, cond).loginfo, "expected symbol ')' during #if evaluation\n"); + goto eval_fail; + } + goto done_complete_acc; + } + if (op_lvl == OPLVL_BOR) { + // op_typ == OPLVL_BOR + vector_last(ppeaux, stack).st_bool = 1; + if (!acc) goto done_partial_eval; + // We have four possibilities: + // [!0] || x ~> 1 + // [!0] || x) ~> 1) + // [!0] || x ? y : z ~> z + // [!0] || x : y ~> 1 : y ~> 1 + // We are at the '||'; note that we know the top of the stack has no pending operation + unsigned nparens = 0; + for (++tok; tok < vector_end(preproc, cond); ++tok) { + if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) { + ++nparens; + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_RPAREN)) { + if (nparens) --nparens; + else { + if (vector_size(ppeaux, stack) == 1) { + log_error(&tok->loginfo, "unexpected symbol ')' (parenthesis not opened) during #if evaluation\n"); + goto eval_fail; + } + if (vector_last(ppeaux, stack).n_colons) { + log_error(&tok->loginfo, "unexpected symbol ')', expected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + + acc = 1; + goto eval_rparen_acc; + } + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) { + if (!nparens) { + acc = 1; + goto eval_question_acc; + } + } else if ((tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_COLON)) { + if (!nparens) { + if (!vector_last(ppeaux, stack).n_colons) { + log_error(&tok->loginfo, "unexpected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + acc = 1; + goto eval_colon_acc; + } } - } else if (!nparens && (tok->tokt == PPTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) { - goto eval_question_acc; } - } - if (tok == vector_end(preproc, cond)) { - if (!nparens) goto done_complete_acc; - else { - printf("Unclosed parenthesis in #if evaluation\n"); + if (nparens) { + log_error(&vector_last(preproc, cond).loginfo, "expected symbol ')' during #if evaluation\n"); + goto eval_fail; + } + if (vector_last(ppeaux, stack).n_colons) { + log_error(&vector_last(preproc, cond).loginfo, "expected symbol ':' during #if evaluation\n"); + goto eval_fail; + } + if (vector_size(ppeaux, stack) != 1) { + log_error(&vector_last(preproc, cond).loginfo, "expected symbol ')' during #if evaluation\n"); goto eval_fail; } + acc = 1; + goto done_complete_acc; } - goto done_partial_eval; + log_internal(&li0, "invalid op_lvl %d during #if evaluation\n", op_lvl); + goto eval_fail; } - // if (vector_last(ppeaux, stack).st_bool) { - // acc = !!acc; - // vector_last(ppeaux, stack).st_bool = 0; - // } -#pragma GCC diagnostic pop - printf(" Invalid op_lvl %d > 11 during #if evaluation\n", op_lvl); - goto eval_fail; done_partial_eval: } else { - printf("Invalid token type %u during #if evaluation\n", tok->tokt); + log_error(&tok->loginfo, "invalid token type %u during #if evaluation\n", tok->tokt); goto eval_fail; } @@ -1740,7 +1806,8 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i else if (sym == SYM_EXCL) acc = !acc; else if (sym == SYM_TILDE) acc = ~acc; else { - printf(" Unknown level 1 unary operator sym ID %u\n", sym); + log_internal(&vector_last(ppeaux, stack).v1[vector_last(ppeaux, stack).st1].loginfo, + "unknown level 1 unary operator sym ID %u\n", sym); } } vector_last(ppeaux, stack).v0 = acc; @@ -1749,114 +1816,16 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_i } if (vector_size(ppeaux, stack) != 1) { - printf("Opened parenthesis never closed in #if expression\n"); + log_error(&vector_last(preproc, cond).loginfo, "expected symbol ')' during #if evaluation\n"); goto eval_fail; } done_complete_stack: - acc = vector_last(ppeaux, stack).v0; - vector_last(ppeaux, stack).st0 = 0; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wduplicated-cond" // For the else if (.stX) - if (vector_last(ppeaux, stack).st2 == OPTYP_MUL) { - acc = vector_last(ppeaux, stack).v2 * acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2 == OPTYP_DIV) { - if (!acc) { - printf("Error: division by zero\n"); - goto eval_fail; - } - acc = vector_last(ppeaux, stack).v2 / acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2 == OPTYP_MOD) { - if (!acc) { - printf("Error: division by zero\n"); - goto eval_fail; - } - acc = vector_last(ppeaux, stack).v2 % acc; - vector_last(ppeaux, stack).st2 = 0; - } else if (vector_last(ppeaux, stack).st2) { - printf(" Unknown st2 %d during #if evaluation\n", vector_last(ppeaux, stack).st2); - goto eval_fail; - } - if (vector_last(ppeaux, stack).st3 == OPTYP_ADD) { - acc = vector_last(ppeaux, stack).v3 + acc; - vector_last(ppeaux, stack).st3 = 0; - } else if (vector_last(ppeaux, stack).st3 == OPTYP_SUB) { - acc = vector_last(ppeaux, stack).v3 - acc; - vector_last(ppeaux, stack).st3 = 0; - } else if (vector_last(ppeaux, stack).st3) { - printf(" Unknown st3 %d during #if evaluation\n", vector_last(ppeaux, stack).st3); - goto eval_fail; - } - if (vector_last(ppeaux, stack).st4 == OPTYP_LSL) { - acc = vector_last(ppeaux, stack).v4 << acc; - vector_last(ppeaux, stack).st4 = 0; - } else if (vector_last(ppeaux, stack).st4 == OPTYP_LSR) { - acc = is_unsigned ? (int64_t)((uint64_t)vector_last(ppeaux, stack).v4 >> (uint64_t)acc) : (vector_last(ppeaux, stack).v4 >> acc); - vector_last(ppeaux, stack).st4 = 0; - } else if (vector_last(ppeaux, stack).st4) { - printf(" Unknown st4 %d during #if evaluation\n", vector_last(ppeaux, stack).st4); - goto eval_fail; - } - if (vector_last(ppeaux, stack).st5 == OPTYP_LET) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 < (uint64_t)acc) : (vector_last(ppeaux, stack).v5 < acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_LEE) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 <= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 <= acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_GRT) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 > (uint64_t)acc) : (vector_last(ppeaux, stack).v5 > acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5 == OPTYP_GRE) { - acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 >= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 >= acc); - is_unsigned = 0; - vector_last(ppeaux, stack).st5 = 0; - } else if (vector_last(ppeaux, stack).st5) { - printf(" Unknown st5 %d during #if evaluation\n", vector_last(ppeaux, stack).st5); - goto eval_fail; - } - if (vector_last(ppeaux, stack).st6 == OPTYP_EQU) { - acc = vector_last(ppeaux, stack).v6 == acc; - vector_last(ppeaux, stack).st6 = 0; - } else if (vector_last(ppeaux, stack).st6 == OPTYP_NEQ) { - acc = vector_last(ppeaux, stack).v6 != acc; - vector_last(ppeaux, stack).st6 = 0; - } else if (vector_last(ppeaux, stack).st6) { - printf(" Unknown st6 %d during #if evaluation\n", vector_last(ppeaux, stack).st6); + success = 1; + acc = eval_stack(&vector_last(ppeaux, stack), li0, OPLVL_ALS, 0, is_unsigned, &success); + if (!success) { goto eval_fail; } - if (vector_last(ppeaux, stack).st7 == OPTYP_AAN) { - acc = vector_last(ppeaux, stack).v7 & acc; - vector_last(ppeaux, stack).st7 = 0; - } else if (vector_last(ppeaux, stack).st7) { - printf(" Unknown st7 %d during #if evaluation\n", vector_last(ppeaux, stack).st7); - goto eval_fail; - } - if (vector_last(ppeaux, stack).st8 == OPTYP_XOR) { - acc = vector_last(ppeaux, stack).v8 ^ acc; - vector_last(ppeaux, stack).st8 = 0; - } else if (vector_last(ppeaux, stack).st8) { - printf(" Unknown st8 %d during #if evaluation\n", vector_last(ppeaux, stack).st8); - goto eval_fail; - } - if (vector_last(ppeaux, stack).st9 == OPTYP_AOR) { - acc = vector_last(ppeaux, stack).v9 | acc; - vector_last(ppeaux, stack).st9 = 0; - } else if (vector_last(ppeaux, stack).st9) { - printf(" Unknown st9 %d during #if evaluation\n", vector_last(ppeaux, stack).st9); - goto eval_fail; - } - if (vector_last(ppeaux, stack).st_bool) { - acc = !!acc; - vector_last(ppeaux, stack).st_bool = 0; - } -#pragma GCC diagnostic pop done_complete_acc: vector_del(ppeaux, stack); @@ -1869,7 +1838,7 @@ int proc_unget_token(preproc_t *src, proc_token_t *tok) { } static proc_token_t proc_next_token_aux(preproc_t *src) { if (!vector_size(ppsource, src->prep)) { - return (proc_token_t){ .tokt = PTOK_EOF, .tokv = {.c = (char)EOF} }; + return (proc_token_t){ .tokt = PTOK_EOF, .loginfo = { 0 }, .tokv = {.c = (char)EOF} }; } if (vector_last(ppsource, src->prep).srct == PPSRC_PTOKEN) { proc_token_t ret = vector_last(ppsource, src->prep).srcv.ptok; @@ -1879,7 +1848,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { check_if_depth: { if (!vector_size(ppsource, src->prep)) { - return (proc_token_t){ .tokt = PTOK_EOF, .tokv = {.c = (char)EOF} }; + return (proc_token_t){ .tokt = PTOK_EOF, .loginfo = { 0 }, .tokv = {.c = (char)EOF} }; } ppsource_t *ppsrc = &vector_last(ppsource, src->prep); if ((ppsrc->srct == PPSRC_PREPARE) && (ppsrc->srcv.prep.ok_depth != ppsrc->srcv.prep.cond_depth)) { @@ -1896,12 +1865,13 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { src->st = PPST_NONE; proc_token_t ret; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = tok.tokv.c; return ret; } else if (tok.tokt == PPTOK_NEWLINE) { src->st = PPST_NL; } else if (tok.tokt == PPTOK_EOF) { - printf("Error: file ended before closing all conditionals (ignoring)\n"); + log_warning(&tok.loginfo, "file ended before closing all conditionals (ignoring)\n"); vector_pop(ppsource, src->prep); goto check_if_depth; } else if ((tok.tokt == PPTOK_SYM) && (src->st == PPST_NL) && (tok.tokv.sym == SYM_HASH)) { @@ -1938,36 +1908,40 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); VECTOR(preproc) *cond = vector_new(preproc); if (!cond) { - printf("Error: failed to allocate #elif condition vector\n"); + log_memory("failed to allocate #elif condition vector\n"); src->st = PPST_NONE; - return (proc_token_t){ .tokt = PTOK_INVALID, .tokv = {.c = '\0'} }; + return (proc_token_t){ .tokt = PTOK_INVALID, .loginfo = tok.loginfo, .tokv = {.c = '\0'} }; } tok = ppsrc_next_token(src); + loginfo_t li = tok.loginfo; while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { + li.lineno_end = tok.loginfo.lineno_end ? tok.loginfo.lineno_end : tok.loginfo.lineno; + li.colno_end = tok.loginfo.colno_end ? tok.loginfo.colno_end : tok.loginfo.colno; if (!vector_push(preproc, cond, tok)) { - printf("Error: failed to add token to #elif condition vector\n"); + log_memory("failed to add token to #elif condition vector\n"); vector_del(preproc, cond); src->st = PPST_NONE; - return (proc_token_t){ .tokt = PTOK_INVALID, .tokv = {.c = '\0'} }; + return (proc_token_t){ .tokt = PTOK_INVALID, .loginfo = tok.loginfo, .tokv = {.c = '\0'} }; } tok = ppsrc_next_token(src); } vector_trim(preproc, cond); khash_t(string_set) *solved_macros = kh_init(string_set); if (!solved_macros) { - printf("Error: failed to allocate #elif solved_macros set\n"); + log_memory("failed to allocate #elif solved_macros set\n"); vector_del(preproc, cond); src->st = PPST_NONE; - return (proc_token_t){ .tokt = PTOK_INVALID, .tokv = {.c = '\0'} }; + return (proc_token_t){ .tokt = PTOK_INVALID, .loginfo = tok.loginfo, .tokv = {.c = '\0'} }; } - VECTOR(preproc) *expanded = proc_do_expand(src->macros_map, cond, solved_macros, src->macros_used); + VECTOR(preproc) *expanded = preproc_do_expand(&li, src->macros_map, cond, solved_macros, src->macros_used); vector_del(preproc, cond); macros_set_del(solved_macros); if (!expanded) { - printf("Error: failed to expand #elif condition\n"); + // Not required as preproc_do_expand already prints an error, but this can be useful + log_error(&li, "failed to expand #elif condition\n"); src->st = PPST_NONE; - return (proc_token_t){ .tokt = PTOK_INVALID, .tokv = {.c = '\0'} }; + return (proc_token_t){ .tokt = PTOK_INVALID, .loginfo = tok.loginfo, .tokv = {.c = '\0'} }; } // Now we need to compute what is pointed by expanded, and increase cond_depth and ok_depth as needed @@ -1975,7 +1949,8 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { int64_t res = preproc_eval(expanded, &st, src->target->size_long == 4); vector_del(preproc, expanded); if (!st) { - printf("Error: failed to evaluate #elif condition in (%s)\n", src->cur_file); + // Not required as preproc_eval already prints an error, but this can be useful + log_error(&li, "failed to evaluate #elif condition\n"); src->st = PPST_NONE; return (proc_token_t){ .tokt = PTOK_INVALID, .tokv = {.c = '\0'} }; } @@ -1992,7 +1967,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } } if (tok.tokt == PPTOK_EOF) { - printf("Error: file ended before closing all conditionals (ignoring)\n"); + log_warning(&tok.loginfo, "file ended before closing all conditionals (ignoring)\n"); vector_pop(ppsource, src->prep); src->st = PPST_NL; // Should be redundant since TOK_NEWLINE is added before TOK_EOF if required // EOF has an empty destructor @@ -2007,7 +1982,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid token type %u after '#elifdef' preprocessor command\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after '#elifdef' preprocessor command\n", tok.tokt); goto preproc_ignore_remaining; } if ((ppsrc->srcv.prep.ok_depth == ppsrc->srcv.prep.cond_depth - 1) && !ppsrc->srcv.prep.entered_next_ok_cond) { @@ -2023,7 +1998,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid token type %u after '#elifdef' preprocessor command\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after '#elifdef' preprocessor command\n", tok.tokt); goto preproc_ignore_remaining; } if ((ppsrc->srcv.prep.ok_depth == ppsrc->srcv.prep.cond_depth - 1) && !ppsrc->srcv.prep.entered_next_ok_cond) { @@ -2061,7 +2036,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { goto preproc_ignore_remaining_goto; } - printf("Unknown ignored pp command %s (%s), skipping until EOL\n", string_content(tok.tokv.str), src->cur_file); + log_warning(&tok.loginfo, "Unknown ignored pp command %s, skipping until EOL\n", string_content(tok.tokv.str)); preproc_ignore_remaining: while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { preproc_token_del(&tok); @@ -2092,6 +2067,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { check_next_token: if (!vector_size(ppsource, src->prep)) { ret.tokt = PTOK_EOF; + ret.loginfo = (loginfo_t){0}; ret.tokv.c = (char)EOF; return ret; } @@ -2102,6 +2078,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { case PPTOK_INVALID: src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = tok.tokv.c; return ret; case PPTOK_IDENT: @@ -2112,6 +2089,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { macro_t *m = &kh_val(src->macros_map, it); int need_solve = !m->is_funlike; VECTOR(preprocs) *margs = NULL; + loginfo_t li = tok.loginfo; if (m->is_funlike) { preproc_token_t tok2 = ppsrc_next_token(src); size_t nnls = 0; @@ -2146,13 +2124,16 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { if ((tok2.tokt == PPTOK_SYM) && (tok2.tokv.sym == SYM_LPAREN)) ++need_solve; else if ((tok2.tokt == PPTOK_SYM) && (tok2.tokv.sym == SYM_RPAREN)) --need_solve; } + li.lineno_end = tok2.loginfo.lineno_end ? tok2.loginfo.lineno_end : tok2.loginfo.lineno; + li.colno_end = tok2.loginfo.colno_end ? tok2.loginfo.colno_end : tok2.loginfo.colno; if (need_solve) { - printf("Unfinished fun-like macro %s\n", string_content(tok.tokv.str)); + log_error(&li, "unfinished function-like macro %s\n", string_content(tok.tokv.str)); vector_del(preprocs, margs); vector_del(preproc, marg); string_del(tok.tokv.str); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok2.loginfo; ret.tokv.c = tok.tokv.c; return ret; } @@ -2166,11 +2147,12 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { need_solve = 1; } else { if (!vector_reserve(ppsource, src->prep, vector_size(ppsource, src->prep) + nnls + 1)) { - printf("Memory error (undoing lookahead for macro use %s)\n", string_content(tok.tokv.str)); + log_memory("undoing lookahead for macro use %s\n", string_content(tok.tokv.str)); string_del(tok.tokv.str); preproc_token_del(&tok2); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = li; ret.tokv.c = '\0'; return ret; } @@ -2189,22 +2171,24 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { char *mname = string_steal(tok.tokv.str); - VECTOR(preproc) *solved = proc_solve_macro(src->macros_map, mname, m, margs, solved_macros, NULL); + VECTOR(preproc) *solved = preproc_solve_macro(&li, src->macros_map, mname, m, margs, solved_macros, NULL); if (margs) vector_del(preprocs, margs); macros_set_del(solved_macros); if (!solved) { src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = li; ret.tokv.c = '\0'; return ret; } // If the expansion is empty, don't push it if (vector_size(preproc, solved)) { if (!vector_push(ppsource, src->prep, ((ppsource_t){.srct = PPSRC_PPTOKENS, .srcv.pptoks = {.idx = 0, .toks = solved}}))) { - printf("Memory error (pushing expanded macro)\n"); + log_memory("pushing expanded macro\n"); vector_del(preproc, solved); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = li; ret.tokv.c = '\0'; return ret; } @@ -2219,11 +2203,12 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { if (0) { solve_err_mem: - printf("Memory error (parsing macro use %s)\n", string_content(tok.tokv.str)); + log_memory("parsing macro use %s\n", string_content(tok.tokv.str)); if (margs) vector_del(preprocs, margs); string_del(tok.tokv.str); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = li; ret.tokv.c = '\0'; return ret; } @@ -2240,20 +2225,24 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { ret.tokt = PTOK_KEYWORD; ret.tokv.kw = kh_val(str2kw, it); } + ret.loginfo = tok.loginfo; return ret; } case PPTOK_NUM: src->st = (src->st == PPST_PRAGMA_EXPLICIT) ? PPST_PRAGMA_EXPLICIT : PPST_NONE; ret.tokt = PTOK_NUM; + ret.loginfo = tok.loginfo; ret.tokv.str = tok.tokv.str; return ret; case PPTOK_STRING: src->st = (src->st == PPST_PRAGMA_EXPLICIT) ? PPST_PRAGMA_EXPLICIT : PPST_NONE; ret.tokt = PTOK_STRING; + ret.loginfo = tok.loginfo; ret.tokv = (union proc_token_val_u){.sstr = tok.tokv.sstr, .sisstr = tok.tokv.sisstr}; return ret; case PPTOK_INCL: src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = tok.tokv.sisstr ? '<' : '"'; string_del(tok.tokv.sstr); return ret; @@ -2262,19 +2251,14 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { tok = ppsrc_next_token(src); if ((tok.tokt == PPTOK_NEWLINE) || (tok.tokt == PPTOK_EOF)) { // Empty preprocessor command - if (tok.tokt == PPTOK_NEWLINE) { - ret.tokt = PTOK_EOF; - ret.tokv.c = tok.tokv.c; - return ret; - } else { - goto check_next_token; - } + goto start_cur_token; } if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) goto preproc_hash_err; if (!strcmp(string_content(tok.tokv.str), "include") || !strcmp(string_content(tok.tokv.str), "include_next")) { int is_next = string_content(tok.tokv.str)[7] == '_'; string_del(tok.tokv.str); tok = ppsrc_next_token(src); + loginfo_t li = tok.loginfo; string_t *incl_file; int is_sys; if (tok.tokt == PPTOK_INCL) { @@ -2282,48 +2266,59 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { // Assume we only have one #include "..." path, so include_next is always a system include is_sys = is_next || !tok.tokv.sisstr; tok = ppsrc_next_token(src); // Token was moved + loginfo_t ignored_infos = tok.loginfo; int has_ignored = 0; while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { - printf("Warning: ignored tokens after #include directive (%s)\n", src->cur_file); + has_ignored = 1; + ignored_infos.lineno_end = tok.loginfo.lineno_end ? tok.loginfo.lineno_end : tok.loginfo.lineno; + ignored_infos.colno_end = tok.loginfo.colno_end ? tok.loginfo.colno_end : tok.loginfo.colno; preproc_token_del(&tok); tok = ppsrc_next_token(src); } + if (has_ignored) { + log_warning(&ignored_infos, "ignored tokens after #include%s directive\n", is_next ? "_next" : ""); + } } else { // Expand macro, then try again VECTOR(preproc) *incl = vector_new(preproc); if (!incl) { - printf("Error: failed to allocate #include tokens vector (%s)\n", src->cur_file); + log_memory("failed to allocate #include tokens vector\n"); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { if (!vector_push(preproc, incl, tok)) { - printf("Error: failed to add token to #include tokens vector (%s)\n", src->cur_file); + log_memory("failed to add token to #include tokens vector\n"); vector_del(preproc, incl); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } + li.lineno_end = tok.loginfo.lineno_end ? tok.loginfo.lineno_end : tok.loginfo.lineno; + li.colno_end = tok.loginfo.colno_end ? tok.loginfo.colno_end : tok.loginfo.colno; tok = ppsrc_next_token(src); } vector_trim(preproc, incl); khash_t(string_set) *solved_macros = kh_init(string_set); if (!solved_macros) { - printf("Error: failed to allocate #include solved_macros set (%s)\n", src->cur_file); + log_memory("failed to allocate #include solved_macros set\n"); vector_del(preproc, incl); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } - VECTOR(preproc) *expanded = proc_do_expand(src->macros_map, incl, solved_macros, src->macros_used); + VECTOR(preproc) *expanded = preproc_do_expand(&li, src->macros_map, incl, solved_macros, src->macros_used); vector_del(preproc, incl); macros_set_del(solved_macros); if (!expanded) { - printf("Error: failed to expand #include tokens (%s)\n", src->cur_file); + log_error(&li, "failed to expand #include tokens\n"); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; ret.tokv.c = '\0'; @@ -2332,27 +2327,27 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { // Now we need to check what is pointed by expanded if (!vector_size(preproc, expanded)) { - printf("Error: missing #include name (%s)\n", src->cur_file); + log_error(&li, "missing #include name\n"); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } if (vector_content(preproc, expanded)[0].tokt == PPTOK_STRING) { is_sys = is_next || src->is_sys; preproc_token_t *exp = vector_content(preproc, expanded); - // TODO - printf("Error: TODO: #include (%s)\n", - string_content(exp->tokv.sstr), exp->tokv.sisstr, src->cur_file); + log_error(&li, "TODO: #include \n", string_content(exp->tokv.sstr), exp->tokv.sisstr); vector_del(preproc, expanded); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } else if ((vector_content(preproc, expanded)[0].tokt == PPTOK_SYM) && (vector_content(preproc, expanded)[0].tokv.sym == SYM_LT) && (vector_last(preproc, expanded).tokt == PPTOK_SYM) && (vector_last(preproc, expanded).tokv.sym == SYM_GT) && (vector_size(preproc, expanded) >= 3)) { - printf("Warning: #include command with macro expansion, assuming no space is present in the file name\n"); + log_warning(&li, "#include command with macro expansion, assuming no space is present in the file name\n"); is_sys = 0; incl_file = string_new(); for (vector_preproc_elem *tok2 = expanded->content + 1; tok2 < expanded->content + expanded->vsize - 1; ++tok2) { @@ -2360,26 +2355,26 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { case PPTOK_IDENT: case PPTOK_IDENT_UNEXP: if (!string_add_string(incl_file, tok2->tokv.str)) { - printf("Error: failed to add ident to include string (%s)\n", src->cur_file); + log_memory("failed to add ident to include string\n"); vector_del(preproc, expanded); string_del(incl_file); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } break; case PPTOK_SYM: - for (const char *s = sym2str[tok2->tokv.sym]; *s; ++s) { - if (!string_add_char(incl_file, *s)) { - printf("Error: failed to add symbol to include string (%s)\n", src->cur_file); - vector_del(preproc, expanded); - string_del(incl_file); - src->st = PPST_NONE; - ret.tokt = PTOK_INVALID; - ret.tokv.c = '\0'; - return ret; - } + if (!string_add_cstr(incl_file, sym2str[tok2->tokv.sym])) { + log_memory("failed to add symbol to include string\n"); + vector_del(preproc, expanded); + string_del(incl_file); + src->st = PPST_NONE; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = '\0'; + return ret; } break; @@ -2392,32 +2387,39 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { case PPTOK_START_LINE_COMMENT: case PPTOK_EOF: default: - printf("Error: TODO: add token type %u to include string (%s)\n", tok2->tokt, src->cur_file); + log_error(&li, "TODO: add token type %u to include string\n", tok2->tokt); vector_del(preproc, expanded); string_del(incl_file); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } } vector_del(preproc, expanded); } else { - printf("Error: invalid #include command (macro expansion does not result in string or <...>) (%s)\n", src->cur_file); + log_error(&li, "invalid #include command (macro expansion does not result in string or <...>)\n"); vector_del(preproc, expanded); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } } // cur_pathno == 0 if cur_file was from an #include "...", otherwise idx + 1 +#ifdef LOG_INCLUDE + printf("Opening %s as %s from system path %zu\n", string_content(incl_file), + is_sys ? "system header" : "cur header", is_next ? src->cur_pathno : 0); +#endif if ((is_sys || !try_open_dir(src, incl_file)) && !try_open_sys(src, incl_file, is_next ? src->cur_pathno : 0)) { - printf("Failed to open %s\n", string_content(incl_file)); + log_error(&li, "failed to open %s\n", string_content(incl_file)); string_del(incl_file); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; - ret.tokv.c = tok.tokv.sisstr ? '<' : '"'; + ret.loginfo = li; + ret.tokv.c = is_sys ? '<' : '"'; return ret; } string_del(incl_file); @@ -2427,16 +2429,17 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid token type %u after '#define' preprocessor command\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after '#define' preprocessor command\n", tok.tokt); goto preproc_hash_err; } string_t *defname = tok.tokv.str; macro_t m = (macro_t){ .is_funlike = 0, .has_varargs = 0, .nargs = 0, .toks = vector_new(mtoken) }; if (!m.toks) { - printf("Failed to allocate token vector for macro %s, returning EOF\n", string_content(defname)); + log_memory("failed to allocate token vector for macro %s\n", string_content(defname)); string_del(defname); // Token is now freed - ret.tokt = PTOK_EOF; - ret.tokv.c = (char)EOF; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = '\0'; return ret; } khash_t(argid_map) *args = NULL; @@ -2445,11 +2448,12 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { m.is_funlike = 1; args = kh_init(argid_map); if (!args) { - printf("Failed to allocate args map for macro %s, returning EOF\n", string_content(defname)); + log_memory("failed to allocate args map for macro %s\n", string_content(defname)); string_del(defname); // Token is now freed vector_del(mtoken, m.toks); - ret.tokt = PTOK_EOF; - ret.tokv.c = (char)EOF; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = '\0'; return ret; } m.nargs = 0; @@ -2466,17 +2470,18 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { char *tok_str = strdup("__VA_ARGS__"); khiter_t kh_k = kh_put(argid_map, args, tok_str, &kh_ret); // Moves the string content if (kh_ret < 0) { // Failed to move, needs to free here - printf("Failed to push arg %s for macro %s, returning EOF\n", tok_str, string_content(defname)); + log_memory("failed to push arg %s for macro %s\n", tok_str, string_content(defname)); string_del(defname); free(tok_str); vector_del(mtoken, m.toks); argid_map_del(args); - ret.tokt = PTOK_EOF; - ret.tokv.c = (char)EOF; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = '\0'; return ret; } if (kh_ret == 0) { - printf("Duplicate arg %s defining macro %s\n", tok_str, string_content(defname)); + log_error(&tok.loginfo, "duplicate argument name %s defining macro %s\n", tok_str, string_content(defname)); string_del(defname); vector_del(mtoken, m.toks); argid_map_del(args); @@ -2486,7 +2491,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { // Empty token destructor tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_RPAREN)) { - printf("Invalid token type %u after variadic macro arguments definition\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after variadic macro arguments definition\n", tok.tokt); string_del(defname); vector_del(mtoken, m.toks); argid_map_del(args); @@ -2499,17 +2504,18 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { char *tok_str = string_steal(tok.tokv.str); khiter_t kh_k = kh_put(argid_map, args, tok_str, &kh_ret); // Moves the string content if (kh_ret < 0) { // Failed to move, needs to free here - printf("Failed to push arg %s for macro %s, returning EOF\n", tok_str, string_content(defname)); + log_memory("failed to push arg %s for macro %s\n", tok_str, string_content(defname)); string_del(defname); free(tok_str); vector_del(mtoken, m.toks); argid_map_del(args); - ret.tokt = PTOK_EOF; - ret.tokv.c = (char)EOF; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = '\0'; return ret; } if (kh_ret == 0) { - printf("Duplicate arg %s defining macro %s\n", tok_str, string_content(defname)); + log_error(&tok.loginfo, "duplicate argument name %s defining macro %s\n", tok_str, string_content(defname)); string_del(defname); vector_del(mtoken, m.toks); argid_map_del(args); @@ -2534,7 +2540,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { // Empty token destructor tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_RPAREN)) { - printf("Invalid token type %u after variadic macro arguments definition\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after variadic macro arguments definition\n", tok.tokt); string_del(defname); vector_del(mtoken, m.toks); argid_map_del(args); @@ -2543,7 +2549,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { ok = 1; break; } else { - printf("Invalid %s type %u during variadic macro arguments definition\n", + log_error(&tok.loginfo, "invalid %s type %u in macro arguments definition\n", (tok.tokt == PPTOK_SYM) ? "symbol" : "token", (tok.tokt == PPTOK_SYM) ? tok.tokv.sym : tok.tokt); string_del(defname); @@ -2552,7 +2558,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { goto preproc_hash_err; } } else { - printf("Invalid %s type %u as macro arguments definition name\n", + log_error(&tok.loginfo, "invalid %s type %u as macro arguments definition name\n", (tok.tokt == PPTOK_SYM) ? "symbol" : "token", (tok.tokt == PPTOK_SYM) ? tok.tokv.sym : tok.tokt); string_del(defname); vector_del(mtoken, m.toks); @@ -2562,7 +2568,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } } if (!ok) { - printf("Invalid macro definition for %s\n", string_content(defname)); + log_error(&tok.loginfo, "invalid macro definition for %s\n", string_content(defname)); string_del(defname); vector_del(mtoken, m.toks); argid_map_del(args); @@ -2582,7 +2588,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { if ((tok.tokt == PPTOK_SYM) && (tok.tokv.sym == SYM_HASH)) { if (state & ST_STR) { - printf("Warning: duplicated stringify in macro definition (defining %s)\n", string_content(defname)); + log_warning(&tok.loginfo, "duplicated stringify in macro definition (defining %s)\n", string_content(defname)); } else { state |= ST_STR; } @@ -2592,9 +2598,9 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } if ((tok.tokt == PPTOK_SYM) && (tok.tokv.sym == SYM_HASHHASH)) { if (state & ST_CONCAT) { - printf("Warning: duplicated concatenation in macro definition (defining %s)\n", string_content(defname)); + log_warning(&tok.loginfo, "duplicated concatenation in macro definition (defining %s)\n", string_content(defname)); } else if (!vector_size(mtoken, m.toks)) { - printf("Warning: invalid concatenation at start of macro definition (defining %s)\n", string_content(defname)); + log_warning(&tok.loginfo, "invalid concatenation at start of macro definition (defining %s)\n", string_content(defname)); } else { state |= ST_CONCAT; } @@ -2612,23 +2618,59 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } } if (argid != -1u) { - mtok = mtoken_new_arg(argid, state & ST_STR); // TODO: check for != NULL + mtok = mtoken_new_arg(argid, state & ST_STR); + if (!mtok) { + log_memory("failed to allocate new m-token (defining %s)\n", string_content(defname)); + string_del(defname); + macro_del(&m); + src->st = PPST_NONE; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = tok.tokv.c; + return ret; + } state &= ~ST_STR; } else { - mtok = mtoken_new_token(tok); // Token moved // TODO: check for != NULL + mtok = mtoken_new_token(tok); // Token moved + if (!mtok) { + log_memory("failed to allocate new m-token (defining %s)\n", string_content(defname)); + string_del(defname); + macro_del(&m); + if (tok.tokt == PPTOK_NEWLINE) goto check_next_token; + else goto start_cur_token; + } if (state & ST_STR) { - printf("Warning: invalid stringify before token (defining %s)\n", string_content(defname)); + log_warning(&tok.loginfo, "invalid stringify before token (defining %s)\n", string_content(defname)); state &= ~ST_STR; } } if (state & ST_CONCAT) { mtoken_t *mtok2 = vector_last(mtoken, m.toks); // Guaranteed to exist before setting ST_CONCAT - mtok = mtoken_new_concat(mtok2, mtok); // TODO: check for != NULL + mtok = mtoken_new_concat(mtok2, mtok); + if (!mtok) { + log_memory("failed to allocate new m-token concatenation (defining %s)\n", string_content(defname)); + string_del(defname); + macro_del(&m); + vector_pop_nodel(mtoken, m.toks); + src->st = PPST_NONE; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = tok.tokv.c; + return ret; + } vector_last(mtoken, m.toks) = mtok; state &= ~ST_CONCAT; } else { - // TODO: check for error - vector_push(mtoken, m.toks, mtok); + if (!vector_push(mtoken, m.toks, mtok)) { + log_memory("failed to add m-token (defining %s)\n", string_content(defname)); + string_del(defname); + macro_del(&m); + src->st = PPST_NONE; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = tok.tokv.c; + return ret; + } } // mtok moved to the vector tok = ppsrc_next_token(src); @@ -2638,41 +2680,47 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { if (args) argid_map_del(args); if (tok.tokt == PPTOK_INVALID) { // Abort + log_error(&tok.loginfo, "unexpected invalid input token\n"); string_del(defname); macro_del(&m); - if (tok.tokt == PPTOK_NEWLINE) goto check_next_token; - else goto start_cur_token; + src->st = PPST_NONE; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = tok.tokv.c; + return ret; } else { // NL and EOF have empty destructors khiter_t kh_k; int iret; char *mname_dup = string_steal(defname); - // if (m.is_funlike) printf("OK for %s: %u args", mname_dup, m.nargs); - // else printf("OK for %s: no arg", mname_dup); - // printf("\n"); - // vector_for(mtoken, it, m.toks) { - // printf("Macro token: "); - // print_macro_tok(*it); - // printf("\n"); - // } kh_k = kh_put(string_set, src->macros_defined, mname_dup, &iret); - // TODO: check iret? - if (iret >= 1) { + if (iret < 0) { + // Abort + log_memory("failed to remember macro %s as defined, aborting\n", mname_dup); + free(mname_dup); + macro_del(&m); + src->st = PPST_NONE; + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = tok.tokv.c; + return ret; + } else if (iret > 0) { mname_dup = strdup(mname_dup); } kh_k = kh_put(macros_map, src->macros_map, mname_dup, &iret); if (iret < 0) { // Abort - printf("Failed to remember macro %s, aborting\n", mname_dup); + log_memory("failed to remember macro %s, aborting\n", mname_dup); free(mname_dup); macro_del(&m); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = tok.tokv.c; return ret; } else if (iret == 0) { // Ignore - // Too noisy printf("Duplicated macro %s\n", mname_dup); + // Too noisy log_warning(&tok.loginfo, "Duplicated macro %s\n", mname_dup); free(mname_dup); macro_del(&m); } else { @@ -2685,7 +2733,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid token type %u after '#undef' preprocessor command\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after '#undef' preprocessor command\n", tok.tokt); goto preproc_hash_err; } string_t *mname = tok.tokv.str; @@ -2708,7 +2756,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { if (tok.tokt == PPTOK_NEWLINE) goto check_next_token; else goto start_cur_token; } else if (!strcmp(string_content(tok.tokv.str), "error")) { - printf("Error: #error command (%s):", src->cur_file); + log_error(&tok.loginfo, "#error command:"); string_del(tok.tokv.str); tok = ppsrc_next_token(src); while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { @@ -2740,10 +2788,11 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { printf("\n"); vector_clear(ppsource, src->prep); ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = (char)EOF; return ret; } else if (!strcmp(string_content(tok.tokv.str), "warning")) { - printf("Warning: #warning command (%s):", src->cur_file); + log_warning(&tok.loginfo, "#warning command:"); tok = ppsrc_next_token(src); while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { switch (tok.tokt) { @@ -2754,10 +2803,12 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { case PPTOK_SYM: printf("%s%s", (tok.tokv.sym == SYM_COMMA) ? "" : " ", sym2str[tok.tokv.sym]); break; + case PPTOK_STRING: + printf(" %c%s%c", tok.tokv.sisstr ? '"' : '\'', string_content(tok.tokv.sstr), tok.tokv.sisstr ? '"' : '\''); + break; case PPTOK_INVALID: case PPTOK_NUM: - case PPTOK_STRING: case PPTOK_INCL: case PPTOK_NEWLINE: case PPTOK_BLANK: @@ -2775,15 +2826,16 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Unknown pragma directive, skipping until EOL\n"); + log_error(&tok.loginfo, "unknown pragma directive, skipping until EOL\n"); goto preproc_hash_err; } else if (!strcmp(string_content(tok.tokv.str), "wrappers")) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Unknown pragma wrappers directive, skipping until EOL\n"); + log_error(&tok.loginfo, "unknown pragma wrappers directive, skipping until EOL\n"); goto preproc_hash_err; } else if (!strcmp(string_content(tok.tokv.str), "allow_ints_ext")) { + ret.loginfo = tok.loginfo; while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { preproc_token_del(&tok); tok = ppsrc_next_token(src); @@ -2798,11 +2850,12 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid pragma wrappers explicit_simple directive, skipping until EOL\n"); + log_error(&tok.loginfo, "invalid pragma wrappers explicit_simple directive, skipping until EOL\n"); goto preproc_hash_err; } src->st = PPST_NL; ret.tokt = PTOK_PRAGMA; + ret.loginfo = tok.loginfo; ret.tokv.pragma.typ = PRAGMA_SIMPLE_SU; ret.tokv.pragma.val = tok.tokv.str; tok = ppsrc_next_token(src); @@ -2820,11 +2873,12 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid pragma wrappers explicit_simple directive, skipping until EOL\n"); + log_error(&tok.loginfo, "invalid pragma wrappers explicit_simple directive, skipping until EOL\n"); goto preproc_hash_err; } src->st = PPST_PRAGMA_EXPLICIT; ret.tokt = PTOK_PRAGMA; + ret.loginfo = tok.loginfo; ret.tokv.pragma.typ = PRAGMA_EXPLICIT_CONV; ret.tokv.pragma.val = tok.tokv.str; return ret; @@ -2832,69 +2886,78 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid pragma wrappers explicit_simple directive, skipping until EOL\n"); + log_error(&tok.loginfo, "invalid pragma wrappers explicit_simple directive, skipping until EOL\n"); goto preproc_hash_err; } src->st = PPST_PRAGMA_EXPLICIT; ret.tokt = PTOK_PRAGMA; + ret.loginfo = tok.loginfo; ret.tokv.pragma.typ = PRAGMA_EXPLICIT_CONV_STRICT; ret.tokv.pragma.val = tok.tokv.str; return ret; } else { - printf("Unknown pragma wrappers directive '%s', skipping until EOL\n", string_content(tok.tokv.str)); + log_error(&tok.loginfo, "unknown pragma wrappers directive '%s', skipping until EOL\n", string_content(tok.tokv.str)); goto preproc_hash_err; } } else { - printf("Unknown pragma directive '%s', skipping until EOL\n", string_content(tok.tokv.str)); + log_error(&tok.loginfo, "unknown pragma directive '%s', skipping until EOL\n", string_content(tok.tokv.str)); goto preproc_hash_err; } } else if (!strcmp(string_content(tok.tokv.str), "if")) { if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #if source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #if source type %u\n", vector_last(ppsource, src->prep).srct); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } string_del(tok.tokv.str); VECTOR(preproc) *cond = vector_new(preproc); if (!cond) { - printf("Error: failed to allocate #if condition vector\n"); + log_memory("failed to allocate #if condition vector\n"); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } tok = ppsrc_next_token(src); + loginfo_t li = tok.loginfo; while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { if (!vector_push(preproc, cond, tok)) { - printf("Error: failed to add token to #if condition vector\n"); + log_memory("failed to add token to #if condition vector\n"); vector_del(preproc, cond); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } + li.lineno_end = tok.loginfo.lineno_end ? tok.loginfo.lineno_end : tok.loginfo.lineno; + li.colno_end = tok.loginfo.colno_end ? tok.loginfo.colno_end : tok.loginfo.colno; tok = ppsrc_next_token(src); } vector_trim(preproc, cond); khash_t(string_set) *solved_macros = kh_init(string_set); if (!solved_macros) { - printf("Error: failed to allocate #if solved_macros set\n"); + log_memory("failed to allocate #if solved_macros set\n"); vector_del(preproc, cond); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } - VECTOR(preproc) *expanded = proc_do_expand(src->macros_map, cond, solved_macros, src->macros_used); + VECTOR(preproc) *expanded = preproc_do_expand(&li, src->macros_map, cond, solved_macros, src->macros_used); vector_del(preproc, cond); macros_set_del(solved_macros); if (!expanded) { - printf("Error: failed to expand #if condition\n"); + log_error(&li, "Error: failed to expand #if condition\n"); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } @@ -2904,9 +2967,10 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { int64_t res = preproc_eval(expanded, &st, src->target->size_long == 4); vector_del(preproc, expanded); if (!st) { - printf("Error: failed to evaluate #if condition (%s)\n", src->cur_file); + log_error(&li, "Error: failed to evaluate #if condition\n"); src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = '\0'; return ret; } @@ -2922,13 +2986,13 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } } else if (!strcmp(string_content(tok.tokv.str), "ifdef")) { if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #ifdef source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #ifdef source type %u\n", vector_last(ppsource, src->prep).srct); goto preproc_hash_err; } string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid token type %u after '#ifdef' preprocessor command\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after '#ifdef' preprocessor command\n", tok.tokt); goto preproc_hash_err; } khiter_t it = kh_get(macros_map, src->macros_map, string_content(tok.tokv.str)); @@ -2952,13 +3016,13 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } } else if (!strcmp(string_content(tok.tokv.str), "ifndef")) { if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #ifndef source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #ifndef source type %u\n", vector_last(ppsource, src->prep).srct); goto preproc_hash_err; } string_del(tok.tokv.str); tok = ppsrc_next_token(src); if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) { - printf("Invalid token type %u after '#ifndef' preprocessor command\n", tok.tokt); + log_error(&tok.loginfo, "invalid token type %u after '#ifndef' preprocessor command\n", tok.tokt); goto preproc_hash_err; } khiter_t it = kh_get(macros_map, src->macros_map, string_content(tok.tokv.str)); @@ -2983,7 +3047,7 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } else if (!strcmp(string_content(tok.tokv.str), "elif")) { // We are already in an #if or #elif (or #else) with a match, so we need to leave it and go to the very top if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #elif source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #elif source type %u\n", vector_last(ppsource, src->prep).srct); goto preproc_hash_err; } if (vector_last(ppsource, src->prep).srcv.prep.ok_depth) { @@ -2991,13 +3055,13 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { --vector_last(ppsource, src->prep).srcv.prep.ok_depth; goto preproc_hash_err_goto; } else { - printf("Warning: unexpected #elif preprocessor command\n"); + log_warning(&tok.loginfo, "unexpected #elif preprocessor command\n"); goto preproc_hash_err; } } else if (!strcmp(string_content(tok.tokv.str), "elifdef")) { // We are already in an #if or #elif (or #else) with a match, so we need to leave it and go to the very top if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #elifdef source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #elifdef source type %u\n", vector_last(ppsource, src->prep).srct); goto preproc_hash_err; } string_del(tok.tokv.str); @@ -3017,13 +3081,13 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { --vector_last(ppsource, src->prep).srcv.prep.ok_depth; goto preproc_hash_err_goto; } else { - printf("Warning: unexpected #elifdef preprocessor command\n"); + log_warning(&tok.loginfo, "unexpected #elifdef preprocessor command\n"); goto preproc_hash_err; } } else if (!strcmp(string_content(tok.tokv.str), "elifndef")) { // We are already in an #if or #elif (or #else) with a match, so we need to leave it and go to the very top if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #elifndef source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #elifndef source type %u\n", vector_last(ppsource, src->prep).srct); goto preproc_hash_err; } string_del(tok.tokv.str); @@ -3043,13 +3107,13 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { --vector_last(ppsource, src->prep).srcv.prep.ok_depth; goto preproc_hash_err_goto; } else { - printf("Warning: unexpected #elifndef preprocessor command\n"); + log_warning(&tok.loginfo, "unexpected #elifndef preprocessor command\n"); goto preproc_hash_err; } } else if (!strcmp(string_content(tok.tokv.str), "else")) { // We are already in an #if or #elif (or #else) with a match, so we need to leave it and go to the very top if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #else source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #else source type %u\n", vector_last(ppsource, src->prep).srct); goto preproc_hash_err; } if (vector_last(ppsource, src->prep).srcv.prep.ok_depth) { @@ -3057,24 +3121,24 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { --vector_last(ppsource, src->prep).srcv.prep.ok_depth; goto preproc_hash_err_goto; } else { - printf("Warning: unexpected #else preprocessor command\n"); + log_warning(&tok.loginfo, "unexpected #else preprocessor command\n"); goto preproc_hash_err; } } else if (!strcmp(string_content(tok.tokv.str), "endif")) { if (vector_last(ppsource, src->prep).srct != PPSRC_PREPARE) { - printf("Error: invalid #endif source type %u\n", vector_last(ppsource, src->prep).srct); + log_error(&tok.loginfo, "invalid #endif source type %u\n", vector_last(ppsource, src->prep).srct); goto preproc_hash_err; } if (vector_last(ppsource, src->prep).srcv.prep.ok_depth) { --vector_last(ppsource, src->prep).srcv.prep.ok_depth; --vector_last(ppsource, src->prep).srcv.prep.cond_depth; } else { - printf("Warning: unexpected #endif preprocessor command\n"); + log_warning(&tok.loginfo, "unexpected #endif preprocessor command\n"); } goto preproc_hash_err; } - printf("Unknown pp command %s (%s), skipping until EOL\n", string_content(tok.tokv.str), src->cur_file); + log_warning(&tok.loginfo, "Unknown preprocessor command %s, skipping until EOL\n", string_content(tok.tokv.str)); preproc_hash_err: while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) { preproc_token_del(&tok); @@ -3093,12 +3157,14 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { } src->st = (src->st == PPST_PRAGMA_EXPLICIT) ? PPST_PRAGMA_EXPLICIT : PPST_NONE; ret.tokt = PTOK_SYM; + ret.loginfo = tok.loginfo; ret.tokv.sym = tok.tokv.sym; return ret; case PPTOK_NEWLINE: if (src->st == PPST_PRAGMA_EXPLICIT) { src->st = PPST_NL; ret.tokt = PTOK_SYM; + ret.loginfo = tok.loginfo; ret.tokv.sym = SYM_SEMICOLON; return ret; } @@ -3107,18 +3173,22 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { case PPTOK_BLANK: src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = tok.tokv.c; return ret; case PPTOK_START_LINE_COMMENT: src->st = PPST_NONE; ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; ret.tokv.c = tok.tokv.c; return ret; case PPTOK_EOF: if ((vector_last(ppsource, src->prep).srct == PPSRC_PREPARE) && vector_last(ppsource, src->prep).srcv.prep.cond_depth) { - printf("Error: file ended before closing all conditionals (ignoring)\n"); + log_warning(&tok.loginfo, "file ended before closing all conditionals (ignoring)\n"); } - // printf("Closing %s\n", src->cur_file); +#ifdef LOG_CLOSE + printf("Closing %s\n", src->cur_file); +#endif if (vector_last(ppsource, src->prep).srct == PPSRC_PREPARE) { if (src->dirname) free(src->dirname); if (src->cur_file) free(src->cur_file); @@ -3133,7 +3203,9 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { if (src->st == PPST_PRAGMA_EXPLICIT) { src->st = PPST_NL; ret.tokt = PTOK_SYM; + ret.loginfo = (loginfo_t){0}; // The token's loginfo may have been deleted by the vector_pop above ret.tokv.sym = SYM_SEMICOLON; + // Empty destructor return ret; } src->st = PPST_NL; // Should be redundant since TOK_NEWLINE is added before TOK_EOF if required @@ -3142,9 +3214,10 @@ static proc_token_t proc_next_token_aux(preproc_t *src) { goto check_next_token; default: - printf("Unknown next pp token type %u, sending EOF\n", tok.tokt); - ret.tokt = PTOK_EOF; - ret.tokv.c = (char)EOF; + log_error(&tok.loginfo, "unknown preprocessor token type %u, sending INVALID\n", tok.tokt); + ret.tokt = PTOK_INVALID; + ret.loginfo = tok.loginfo; + ret.tokv.c = '\0'; return ret; } } @@ -3155,7 +3228,7 @@ proc_token_t proc_next_token(preproc_t *src) { proc_token_t ret2 = proc_next_token_aux(src); if ((ret2.tokt == PTOK_STRING) && ret2.tokv.sisstr) { if (!string_add_string(ret.tokv.sstr, ret2.tokv.sstr)) { - printf("Error: failed to concatenate adjacent strings\n"); + log_memory("failed to concatenate adjacent strings\n"); string_del(ret.tokv.sstr); string_del(ret2.tokv.sstr); src->st = PPST_NONE; @@ -3164,9 +3237,11 @@ proc_token_t proc_next_token(preproc_t *src) { return ret; } string_del(ret2.tokv.sstr); + ret.loginfo.lineno_end = ret2.loginfo.lineno_end ? ret2.loginfo.lineno_end : ret2.loginfo.lineno; + ret.loginfo.colno_end = ret2.loginfo.colno_end ? ret2.loginfo.colno_end : ret2.loginfo.colno; } else { if (!proc_unget_token(src, &ret2)) { - printf("Error: failed to unget token next to string token\n"); + log_memory("failed to unget token next to string token\n"); string_del(ret.tokv.sstr); proc_token_del(&ret2); src->st = PPST_NONE;