1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Add tradcpp to the repository, and use it as GENCPP (generic preprocessor)

With lots of experimenting, tradcpp (0.4) seems to work way better
than gcc, and it's output is actually valid. We'll go with that for
now.
This commit is contained in:
Jon Trulson 2019-10-30 19:17:24 -06:00
parent 25e98da92e
commit 215be15f16
105 changed files with 6772 additions and 1 deletions

View file

@ -8,5 +8,5 @@ MAINTAINERCLEANFILES = Makefile.in \
config.h.in \
install-sh
SUBDIRS = lib programs doc
SUBDIRS = util lib programs doc

5
cde/util/Makefile.am Normal file
View file

@ -0,0 +1,5 @@
MAINTAINERCLEANFILES = Makefile.in
SUBDIRS = tradcpp

41
cde/util/tradcpp/CHANGES Normal file
View file

@ -0,0 +1,41 @@
release 0.4 (20130713)
- Fix stupid build problem introduced in 0.3.1.
- Accept and ignore -m32, which imake issues willy-nilly on a bunch
of platforms. I thought this had already been done, but apparently
not.
- Don't use the <err.h> functions. There are still people out there
using legacy systems missing them.
- Sort out some more issues pertaining to handling quoted strings.
- Add some more tests.
release 0.3.1 (20130709)
- Don't leak memory and assert if a bad command-line option comes
after a -D or a -include foo.
- Since imake is a principal application for tradcpp and imake carefully
hides what it's doing when you run it, when rejecting an invalid option
be sure to report *what* that option is.
release 0.3 (20130616)
- Don't eval the control expression of the first #if of a block when
already in a false block; it might not be valid. Reported by
Baptiste Daroussin.
- Don't recognize comments within character constants.
- Don't recognize macro argument parentheses or commas within strings,
or within character constants either.
release 0.2 (20130611)
- auto-recognize more builtin PowerPC and mips macros
- pass -Wunused (partly from Baptiste Daroussin)
- allow absolute paths in include files (partly from Baptiste Daroussin)
- don't use getprogname() in the name of portability
- add tests arising from December 2010 tech-toolchain thread (one
from der Mouse, one of mine)
- clean out usage of sys/cdefs.h macros and don't use the implementation
namespace
- make -Wcomment work again
- fix handling of relative includes
- provide a man page
- other minor improvements
release 0.1 (20130610)
- first release, works with at least some imake templates

View file

@ -0,0 +1,26 @@
MAINTAINERCLEANFILES = Makefile.in
bin_PROGRAMS = tradcpp
tradcpp_SOURCES = array.c \
array.h \
config.h \
directive.c \
directive.h \
eval.c \
eval.h \
files.c \
files.h \
inlinedefs.h \
macro.c \
macro.h \
main.c \
mode.h \
output.c \
output.h \
place.c \
place.h \
utils.c \
utils.h \
version.h

View file

@ -0,0 +1,12 @@
# $NetBSD$
PROG= tradcpp
SRCS= main.c \
files.c directive.c eval.c macro.c output.c \
place.c array.c utils.c
WARNS= 5
#DBG=-g
.include <bsd.prog.mk>

33
cde/util/tradcpp/TODO Normal file
View file

@ -0,0 +1,33 @@
not implemented:
- mode.input_allow_dollars.
- column counts do not take tabstops into account.
- mode.output_linenumbers.
- mode.do_depend.
- mode.do_macrolist.
- mode.do_trace.
- warns.endiflabels. (they cause errors)
- warns.unused.
- the -iremap option.
- #line directives.
- $CPP_RESTRICTED
- other environment variables
tidy up:
- get rid of inlinedefs.h
- use of places in and below macro.c is pretty bogus.
- macro code should be reworked.
fix:
- "#if 0 && 1/0" should not crash; fix eval method.
- an unterminated comment is reported as "no newline at end of file"
(which isn't fatal by default)
- quote characters and comment delimiters that are emitted by
macros are not recognized. See:
t34 (should produce a quote and FOO Q)
t35 (similarly, this test may be redundant once it's fixed)
t36 (C(3) should produce nothing)
t37 (BC foo EC should produce nothing)
Joerg says comments like in t36 should be stripped exactly
twice, once when the macro is defined and again when it's
expanded. Note that gcc's cpp -traditional is getting t37
wrong, and it gets t36 wrong with -C.

115
cde/util/tradcpp/array.c Normal file
View file

@ -0,0 +1,115 @@
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#define ARRAYINLINE
#include "array.h"
struct array *
array_create(void)
{
struct array *a;
a = domalloc(sizeof(*a));
array_init(a);
return a;
}
void
array_destroy(struct array *a)
{
array_cleanup(a);
dofree(a, sizeof(*a));
}
void
array_init(struct array *a)
{
a->num = a->max = 0;
a->v = NULL;
}
void
array_cleanup(struct array *a)
{
arrayassert(a->num == 0);
dofree(a->v, a->max * sizeof(a->v[0]));
#ifdef ARRAYS_CHECKED
a->v = NULL;
#endif
}
void
array_setsize(struct array *a, unsigned num)
{
unsigned newmax;
void **newptr;
if (num > a->max) {
newmax = a->max;
while (num > newmax) {
newmax = newmax ? newmax*2 : 4;
}
newptr = dorealloc(a->v, a->max * sizeof(a->v[0]),
newmax * sizeof(a->v[0]));
a->v = newptr;
a->max = newmax;
}
a->num = num;
}
void
array_insert(struct array *a, unsigned index_)
{
unsigned movers;
arrayassert(a->num <= a->max);
arrayassert(index_ < a->num);
movers = a->num - index_;
array_setsize(a, a->num + 1);
memmove(a->v + index_+1, a->v + index_, movers*sizeof(*a->v));
}
void
array_remove(struct array *a, unsigned index_)
{
unsigned movers;
arrayassert(a->num <= a->max);
arrayassert(index_ < a->num);
movers = a->num - (index_ + 1);
memmove(a->v + index_, a->v + index_+1, movers*sizeof(*a->v));
a->num--;
}

279
cde/util/tradcpp/array.h Normal file
View file

@ -0,0 +1,279 @@
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ARRAY_H
#define ARRAY_H
#include "inlinedefs.h" // XXX
#include "utils.h"
#define ARRAYS_CHECKED
#ifdef ARRAYS_CHECKED
#include <assert.h>
#define arrayassert assert
#else
#define arrayassert(x) ((void)(x))
#endif
#ifndef ARRAYINLINE
#define ARRAYINLINE C99INLINE
#endif
////////////////////////////////////////////////////////////
// type and base operations
struct array {
void **v;
unsigned num, max;
};
struct array *array_create(void);
void array_destroy(struct array *);
void array_init(struct array *);
void array_cleanup(struct array *);
ARRAYINLINE unsigned array_num(const struct array *);
ARRAYINLINE void *array_get(const struct array *, unsigned index_);
ARRAYINLINE void array_set(const struct array *, unsigned index_, void *val);
void array_setsize(struct array *, unsigned num);
ARRAYINLINE void array_add(struct array *, void *val, unsigned *index_ret);
void array_insert(struct array *a, unsigned index_);
void array_remove(struct array *a, unsigned index_);
////////////////////////////////////////////////////////////
// inlining for base operations
ARRAYINLINE unsigned
array_num(const struct array *a)
{
return a->num;
}
ARRAYINLINE void *
array_get(const struct array *a, unsigned index_)
{
arrayassert(index_ < a->num);
return a->v[index_];
}
ARRAYINLINE void
array_set(const struct array *a, unsigned index_, void *val)
{
arrayassert(index_ < a->num);
a->v[index_] = val;
}
ARRAYINLINE void
array_add(struct array *a, void *val, unsigned *index_ret)
{
unsigned index_ = a->num;
array_setsize(a, index_+1);
a->v[index_] = val;
if (index_ret != NULL) {
*index_ret = index_;
}
}
////////////////////////////////////////////////////////////
// bits for declaring and defining typed arrays
/*
* Usage:
*
* DECLARRAY_BYTYPE(foo, bar, INLINE) declares "struct foo", which is
* an array of pointers to "bar", plus the operations on it.
*
* DECLARRAY(foo, INLINE) is equivalent to
* DECLARRAY_BYTYPE(fooarray, struct foo, INLINE).
*
* DEFARRAY_BYTYPE and DEFARRAY are the same as DECLARRAY except that
* they define the operations.
*
* The argument INLINE can be used as follows:
*
* 1. For no inlining:
* In foo.h:
* DECLARRAY(foo, );
* In foo.c:
* DEFARRAY(foo, );
*
* 2. To be file-static:
* In foo.c:
* DECLARRAY(foo, static);
* DEFARRAY(foo, static);
*
* 3. To inline using C99:
* In foo.h:
* DECLARRAY(foo, inline);
* DEFARRAY(foo, inline);
*
* 4. To inline with old gcc:
* In foo.h:
* #ifndef FOO_INLINE
* #define FOO_INLINE extern inline
* #endif
* DECLARRAY(foo, );
* DEFARRAY(foo, FOO_INLINE);
* In foo.c:
* #define FOO_INLINE
* #include "foo.h"
*
* 5. To inline such that it works both with old gcc and C99:
* In foo.h:
* #ifndef FOO_INLINE
* #define FOO_INLINE extern inline
* #endif
* DECLARRAY(foo, FOO_INLINE);
* DEFARRAY(foo, FOO_INLINE);
* In foo.c:
* #define FOO_INLINE
* #include "foo.h"
*
* The mechanism in case (4) ensures that an externally linkable
* definition exists.
*/
#define DECLARRAY_BYTYPE(ARRAY, T, INLINE) \
struct ARRAY { \
struct array arr; \
}; \
\
INLINE struct ARRAY *ARRAY##_create(void); \
INLINE void ARRAY##_destroy(struct ARRAY *a); \
INLINE void ARRAY##_init(struct ARRAY *a); \
INLINE void ARRAY##_cleanup(struct ARRAY *a); \
INLINE unsigned ARRAY##_num(const struct ARRAY *a); \
INLINE T *ARRAY##_get(const struct ARRAY *a, unsigned index_); \
INLINE void ARRAY##_set(struct ARRAY *a, unsigned index_, T *val); \
INLINE void ARRAY##_setsize(struct ARRAY *a, unsigned num); \
INLINE void ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret);\
INLINE void ARRAY##_insert(struct ARRAY *a, unsigned index_); \
INLINE void ARRAY##_remove(struct ARRAY *a, unsigned index_)
#define DEFARRAY_BYTYPE(ARRAY, T, INLINE) \
INLINE void \
ARRAY##_init(struct ARRAY *a) \
{ \
array_init(&a->arr); \
} \
\
INLINE void \
ARRAY##_cleanup(struct ARRAY *a) \
{ \
array_cleanup(&a->arr); \
} \
\
INLINE struct \
ARRAY *ARRAY##_create(void) \
{ \
struct ARRAY *a; \
\
a = domalloc(sizeof(*a)); \
ARRAY##_init(a); \
return a; \
} \
\
INLINE void \
ARRAY##_destroy(struct ARRAY *a) \
{ \
ARRAY##_cleanup(a); \
dofree(a, sizeof(*a)); \
} \
\
INLINE unsigned \
ARRAY##_num(const struct ARRAY *a) \
{ \
return array_num(&a->arr); \
} \
\
INLINE T * \
ARRAY##_get(const struct ARRAY *a, unsigned index_) \
{ \
return (T *)array_get(&a->arr, index_); \
} \
\
INLINE void \
ARRAY##_set(struct ARRAY *a, unsigned index_, T *val) \
{ \
array_set(&a->arr, index_, (void *)val); \
} \
\
INLINE void \
ARRAY##_setsize(struct ARRAY *a, unsigned num) \
{ \
array_setsize(&a->arr, num); \
} \
\
INLINE void \
ARRAY##_add(struct ARRAY *a, T *val, unsigned *ret) \
{ \
array_add(&a->arr, (void *)val, ret); \
} \
\
INLINE void \
ARRAY##_insert(struct ARRAY *a, unsigned index_) \
{ \
array_insert(&a->arr, index_); \
} \
\
INLINE void \
ARRAY##_remove(struct ARRAY *a, unsigned index_) \
{ \
array_remove(&a->arr, index_); \
}
#define DECLARRAY(T, INLINE) DECLARRAY_BYTYPE(T##array, struct T, INLINE)
#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE)
#define DESTROYALL_ARRAY(T, INLINE) \
void T##array_destroyall(struct T##array *arr); \
\
INLINE void \
T##array_destroyall(struct T##array *arr) \
{ \
unsigned i, num; \
struct T *t; \
\
num = T##array_num(arr); \
for (i=0; i<num; i++) { \
t = T##array_get(arr, i); \
T##_destroy(t); \
} \
T##array_setsize(arr, 0); \
}
////////////////////////////////////////////////////////////
// basic array types
DECLARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
#endif /* ARRAY_H */

158
cde/util/tradcpp/config.h Normal file
View file

@ -0,0 +1,158 @@
/*-
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Config for predefined macros. If this doesn't do what you want you
* can set any or all of the CONFIG_ defines from the compiler command
* line; or patch the list in main.c; or both.
*/
/*
* Paths
*/
#ifndef CONFIG_LOCALINCLUDE
#define CONFIG_LOCALINCLUDE "/usr/local/include"
#endif
#ifndef CONFIG_SYSTEMINCLUDE
#define CONFIG_SYSTEMINCLUDE "/usr/include"
#endif
/*
* Operating system
*/
#ifndef CONFIG_OS
#if defined(__NetBSD__)
#define CONFIG_OS "__NetBSD__"
#define CONFIG_OS_2 "__unix__"
#elif defined(__FreeBSD__)
#define CONFIG_OS "__FreeBSD__"
#define CONFIG_OS_2 "__unix__"
#elif defined(__OpenBSD__)
#define CONFIG_OS "__OpenBSD__"
#define CONFIG_OS_2 "__unix__"
#elif defined(__DragonFly__)
#define CONFIG_OS "__DragonFly__"
#define CONFIG_OS_2 "__unix__"
#elif defined(__bsdi__)
#define CONFIG_OS "__bsdi__"
#define CONFIG_OS_2 "__unix__"
#elif defined(__sun)
#define CONFIG_OS "__sun"
#define CONFIG_OS_2 "__unix__"
#elif defined(__sgi)
#define CONFIG_OS "__sgi"
#define CONFIG_OS_2 "__unix__"
#elif defined(__SVR4)
#define CONFIG_OS "__SVR4"
#define CONFIG_OS_2 "__unix__"
#elif defined(__APPLE__)
#define CONFIG_OS "__APPLE__"
#define CONFIG_OS_2 "__unix__"
#elif defined(__linux__)
#define CONFIG_OS "__linux__"
#elif defined(__CYGWIN__)
#define CONFIG_OS "__CYGWIN__"
#elif defined(__INTERIX)
#define CONFIG_OS "__INTERIX"
#elif defined(__MINGW32)
#define CONFIG_OS "__MINGW32"
#else
/* we could error... but let's instead assume generic unix */
#define CONFIG_OS "__unix__"
#endif
#endif
/*
* CPU
*/
#ifndef CONFIG_CPU
#if defined(__x86_64__)
#define CONFIG_CPU "__x86_64__"
#define CONFIG_CPU_2 "__amd64__"
#elif defined(__i386__) || defined(__i386)
#define CONFIG_CPU "__i386__"
#define CONFIG_CPU_2 "__i386"
#elif defined(__sparc)
#define CONFIG_CPU "__sparc"
#elif defined(__mips)
#define CONFIG_CPU "__mips"
#elif defined(__mips__)
#define CONFIG_CPU "__mips__"
#elif defined(__mipsel__)
#define CONFIG_CPU "__mipsel__"
#elif defined(__POWERPC__)
#define CONFIG_CPU "__POWERPC__"
#elif defined(__POWERPC__)
#define CONFIG_CPU "__powerpc__"
#elif defined(__PPC__)
#define CONFIG_CPU "__PPC__"
#elif defined(__ppc__)
#define CONFIG_CPU "__ppc__"
#elif defined(__PPC64__)
#define CONFIG_CPU "__PPC64__"
#elif defined(__ppc64__)
#define CONFIG_CPU "__ppc64__"
#elif defined(__ARM__)
#define CONFIG_CPU "__ARM__"
#else
/* let it go */
#endif
#endif
/*
* Other stuff
*/
#ifndef CONFIG_SIZE
#ifdef __LP64__
#define CONFIG_SIZE "__LP64__"
#else
#define CONFIG_SIZE "__ILP32__"
#endif
#endif
#ifndef CONFIG_BINFMT
#ifdef __ELF__
#define CONFIG_BINFMT "__ELF__"
#endif
#endif
/*
* We are __TRADCPP__ by default, but if you want to masquerade as
* some other compiler this is a convenient place to change it.
*/
#ifndef CONFIG_COMPILER
#define CONFIG_COMPILER "__TRADCPP__"
#define CONFIG_COMPILER_MINOR "__TRADCPP_MINOR__"
#endif

View file

@ -0,0 +1,626 @@
/*-
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "utils.h"
#include "mode.h"
#include "place.h"
#include "files.h"
#include "directive.h"
#include "macro.h"
#include "eval.h"
#include "output.h"
struct ifstate {
struct ifstate *prev;
struct place startplace;
bool curtrue;
bool evertrue;
bool seenelse;
};
static struct ifstate *ifstate;
////////////////////////////////////////////////////////////
// common parsing bits
static
void
uncomment(char *buf)
{
char *s, *t, *u = NULL;
bool incomment = false;
bool inesc = false;
bool inquote = false;
char quote = '\0';
for (s = t = buf; *s; s++) {
if (incomment) {
if (s[0] == '*' && s[1] == '/') {
s++;
incomment = false;
}
} else {
if (!inquote && s[0] == '/' && s[1] == '*') {
incomment = true;
} else {
if (inesc) {
inesc = false;
} else if (s[0] == '\\') {
inesc = true;
} else if (!inquote &&
(s[0] == '"' || s[0] == '\'')) {
inquote = true;
quote = s[0];
} else if (inquote && s[0] == quote) {
inquote = false;
}
if (t != s) {
*t = *s;
}
if (!strchr(ws, *t)) {
u = t;
}
t++;
}
}
}
if (u) {
/* end string after last non-whitespace char */
u[1] = '\0';
} else {
*t = '\0';
}
}
static
void
oneword(const char *what, struct place *p2, char *line)
{
size_t pos;
pos = strcspn(line, ws);
if (line[pos] != '\0') {
p2->column += pos;
complain(p2, "Garbage after %s argument", what);
complain_fail();
line[pos] = '\0';
}
}
////////////////////////////////////////////////////////////
// if handling
static
struct ifstate *
ifstate_create(struct ifstate *prev, struct place *p, bool startstate)
{
struct ifstate *is;
is = domalloc(sizeof(*is));
is->prev = prev;
if (p != NULL) {
is->startplace = *p;
} else {
place_setbuiltin(&is->startplace, 1);
}
is->curtrue = startstate;
is->evertrue = is->curtrue;
is->seenelse = false;
return is;
}
static
void
ifstate_destroy(struct ifstate *is)
{
dofree(is, sizeof(*is));
}
static
void
ifstate_push(struct place *p, bool startstate)
{
struct ifstate *newstate;
newstate = ifstate_create(ifstate, p, startstate);
if (!ifstate->curtrue) {
newstate->curtrue = false;
newstate->evertrue = true;
}
ifstate = newstate;
}
static
void
ifstate_pop(void)
{
struct ifstate *is;
is = ifstate;
ifstate = ifstate->prev;
ifstate_destroy(is);
}
static
void
d_if(struct place *p, struct place *p2, char *line)
{
char *expr;
bool val;
struct place p3 = *p2;
size_t oldlen;
expr = macroexpand(p2, line, strlen(line), true);
oldlen = strlen(expr);
uncomment(expr);
/* trim to fit, so the malloc debugging won't complain */
expr = dorealloc(expr, oldlen + 1, strlen(expr) + 1);
if (ifstate->curtrue) {
val = eval(&p3, expr);
} else {
val = 0;
}
ifstate_push(p, val);
dostrfree(expr);
}
static
void
d_ifdef(struct place *p, struct place *p2, char *line)
{
uncomment(line);
oneword("#ifdef", p2, line);
ifstate_push(p, macro_isdefined(line));
}
static
void
d_ifndef(struct place *p, struct place *p2, char *line)
{
uncomment(line);
oneword("#ifndef", p2, line);
ifstate_push(p, !macro_isdefined(line));
}
static
void
d_elif(struct place *p, struct place *p2, char *line)
{
char *expr;
struct place p3 = *p2;
size_t oldlen;
if (ifstate->seenelse) {
complain(p, "#elif after #else");
complain_fail();
}
if (ifstate->evertrue) {
ifstate->curtrue = false;
} else {
expr = macroexpand(p2, line, strlen(line), true);
oldlen = strlen(expr);
uncomment(expr);
/* trim to fit, so the malloc debugging won't complain */
expr = dorealloc(expr, oldlen + 1, strlen(expr) + 1);
ifstate->curtrue = eval(&p3, expr);
ifstate->evertrue = ifstate->curtrue;
dostrfree(expr);
}
}
static
void
d_else(struct place *p, struct place *p2, char *line)
{
(void)p2;
(void)line;
if (ifstate->seenelse) {
complain(p, "Multiple #else directives in one conditional");
complain_fail();
}
ifstate->curtrue = !ifstate->evertrue;
ifstate->evertrue = true;
ifstate->seenelse = true;
}
static
void
d_endif(struct place *p, struct place *p2, char *line)
{
(void)p2;
(void)line;
if (ifstate->prev == NULL) {
complain(p, "Unmatched #endif");
complain_fail();
} else {
ifstate_pop();
}
}
////////////////////////////////////////////////////////////
// macros
static
void
d_define(struct place *p, struct place *p2, char *line)
{
size_t pos, argpos;
struct place p3, p4;
(void)p;
/*
* line may be:
* macro expansion
* macro(arg, arg, ...) expansion
*/
pos = strcspn(line, " \t\f\v(");
if (line[pos] == '(') {
line[pos++] = '\0';
argpos = pos;
pos = pos + strcspn(line+pos, "()");
if (line[pos] == '(') {
p2->column += pos;
complain(p2, "Left parenthesis in macro parameters");
complain_fail();
return;
}
if (line[pos] != ')') {
p2->column += pos;
complain(p2, "Unclosed macro parameter list");
complain_fail();
return;
}
line[pos++] = '\0';
#if 0
if (!strchr(ws, line[pos])) {
p2->column += pos;
complain(p2, "Trash after macro parameter list");
complain_fail();
return;
}
#endif
} else if (line[pos] == '\0') {
argpos = 0;
} else {
line[pos++] = '\0';
argpos = 0;
}
pos += strspn(line+pos, ws);
p3 = *p2;
p3.column += argpos;
p4 = *p2;
p4.column += pos;
if (argpos) {
macro_define_params(p2, line, &p3,
line + argpos, &p4,
line + pos);
} else {
macro_define_plain(p2, line, &p4, line + pos);
}
}
static
void
d_undef(struct place *p, struct place *p2, char *line)
{
(void)p;
uncomment(line);
oneword("#undef", p2, line);
macro_undef(line);
}
////////////////////////////////////////////////////////////
// includes
static
bool
tryinclude(struct place *p, char *line)
{
size_t len;
len = strlen(line);
if (len > 2 && line[0] == '"' && line[len-1] == '"') {
line[len-1] = '\0';
file_readquote(p, line+1);
line[len-1] = '"';
return true;
}
if (len > 2 && line[0] == '<' && line[len-1] == '>') {
line[len-1] = '\0';
file_readbracket(p, line+1);
line[len-1] = '>';
return true;
}
return false;
}
static
void
d_include(struct place *p, struct place *p2, char *line)
{
char *text;
size_t oldlen;
uncomment(line);
if (tryinclude(p, line)) {
return;
}
text = macroexpand(p2, line, strlen(line), false);
oldlen = strlen(text);
uncomment(text);
/* trim to fit, so the malloc debugging won't complain */
text = dorealloc(text, oldlen + 1, strlen(text) + 1);
if (tryinclude(p, text)) {
dostrfree(text);
return;
}
complain(p, "Illegal #include directive");
complain(p, "Before macro expansion: #include %s", line);
complain(p, "After macro expansion: #include %s", text);
dostrfree(text);
complain_fail();
}
static
void
d_line(struct place *p, struct place *p2, char *line)
{
(void)p2;
(void)line;
/* XXX */
complain(p, "Sorry, no #line yet");
}
////////////////////////////////////////////////////////////
// messages
static
void
d_warning(struct place *p, struct place *p2, char *line)
{
char *msg;
msg = macroexpand(p2, line, strlen(line), false);
complain(p, "#warning: %s", msg);
if (mode.werror) {
complain_fail();
}
dostrfree(msg);
}
static
void
d_error(struct place *p, struct place *p2, char *line)
{
char *msg;
msg = macroexpand(p2, line, strlen(line), false);
complain(p, "#error: %s", msg);
complain_fail();
dostrfree(msg);
}
////////////////////////////////////////////////////////////
// other
static
void
d_pragma(struct place *p, struct place *p2, char *line)
{
(void)p2;
complain(p, "#pragma %s", line);
complain_fail();
}
////////////////////////////////////////////////////////////
// directive table
static const struct {
const char *name;
bool ifskip;
void (*func)(struct place *, struct place *, char *line);
} directives[] = {
{ "define", true, d_define },
{ "elif", false, d_elif },
{ "else", false, d_else },
{ "endif", false, d_endif },
{ "error", true, d_error },
{ "if", false, d_if },
{ "ifdef", false, d_ifdef },
{ "ifndef", false, d_ifndef },
{ "include", true, d_include },
{ "line", true, d_line },
{ "pragma", true, d_pragma },
{ "undef", true, d_undef },
{ "warning", true, d_warning },
};
static const unsigned numdirectives = HOWMANY(directives);
static
void
directive_gotdirective(struct place *p, char *line)
{
struct place p2;
size_t len, skip;
unsigned i;
p2 = *p;
for (i=0; i<numdirectives; i++) {
len = strlen(directives[i].name);
if (!strncmp(line, directives[i].name, len) &&
strchr(ws, line[len])) {
if (directives[i].ifskip && !ifstate->curtrue) {
return;
}
skip = len + strspn(line+len, ws);
p2.column += skip;
line += skip;
len = strlen(line);
len = notrailingws(line, len);
if (len < strlen(line)) {
line[len] = '\0';
}
directives[i].func(p, &p2, line);
return;
}
}
/* ugh. allow # by itself, including with a comment after it */
uncomment(line);
if (line[0] == '\0') {
return;
}
skip = strcspn(line, ws);
complain(p, "Unknown directive #%.*s", (int)skip, line);
complain_fail();
}
/*
* Check for nested comment delimiters in LINE.
*/
static
size_t
directive_scancomments(const struct place *p, char *line, size_t len)
{
size_t pos;
bool incomment;
struct place p2;
p2 = *p;
incomment = 0;
for (pos = 0; pos+1 < len; pos++) {
if (line[pos] == '/' && line[pos+1] == '*') {
if (incomment) {
complain(&p2, "Warning: %c%c within comment",
'/', '*');
if (mode.werror) {
complain_failed();
}
} else {
incomment = true;
}
pos++;
} else if (line[pos] == '*' && line[pos+1] == '/') {
if (incomment) {
incomment = false;
} else {
/* stray end-comment; should we care? */
}
pos++;
}
if (line[pos] == '\n') {
p2.line++;
p2.column = 0;
} else {
p2.column++;
}
}
/* multiline comments are supposed to arrive in a single buffer */
assert(!incomment);
return len;
}
void
directive_gotline(struct place *p, char *line, size_t len)
{
size_t skip;
if (warns.nestcomment) {
directive_scancomments(p, line, len);
}
/* check if we have a directive line (# exactly in column 0) */
if (line[0] == '#') {
skip = 1 + strspn(line + 1, ws);
assert(skip <= len);
p->column += skip;
assert(line[len] == '\0');
directive_gotdirective(p, line+skip /*, length = len-skip */);
p->column += len-skip;
} else if (ifstate->curtrue) {
macro_sendline(p, line, len);
p->column += len;
}
}
void
directive_goteof(struct place *p)
{
while (ifstate->prev != NULL) {
complain(p, "Missing #endif");
complain(&ifstate->startplace, "...opened at this point");
complain_failed();
ifstate_pop();
}
macro_sendeof(p);
}
////////////////////////////////////////////////////////////
// module initialization
void
directive_init(void)
{
ifstate = ifstate_create(NULL, NULL, true);
}
void
directive_cleanup(void)
{
assert(ifstate->prev == NULL);
ifstate_destroy(ifstate);
ifstate = NULL;
}

View file

@ -0,0 +1,39 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
struct place;
void directive_init(void);
void directive_cleanup(void);
void directive_gotline(struct place *p, char *line, size_t len);
void directive_goteof(struct place *p);

765
cde/util/tradcpp/eval.c Normal file
View file

@ -0,0 +1,765 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
//#define DEBUG
#ifdef DEBUG
#include <stdio.h>
#endif
#include "utils.h"
#include "array.h"
#include "mode.h"
#include "place.h"
#include "eval.h"
/*
* e ::=
* e1 ? e2 : e3
* e1 || e2
* e1 && e2
* e1 | e2
* e1 ^ e2
* e1 & e2
* e1 == e2 | e1 != e2
* e1 < e2 | e1 <= e2 | e1 > e2 | e1 >= e2
* e1 << e2 | e1 >> e2
* e1 + e2 | e1 - e2
* e1 * e2 | e1 / e2 | e1 % e2
* !e | ~e | -e | +e
* ( e ) | ident
*/
enum tokens {
T_EOF, /* end of input */
T_VAL, /* value */
T_LPAREN, /* parens */
T_RPAREN,
T_PIPEPIPE, /* operators */
T_AMPAMP,
T_EQEQ,
T_BANGEQ,
T_LTEQ,
T_GTEQ,
T_LTLT,
T_GTGT,
T_QUES,
T_COLON,
T_PIPE,
T_CARET,
T_AMP,
T_LT,
T_GT,
T_PLUS,
T_MINUS,
T_STAR,
T_SLASH,
T_PCT,
T_BANG,
T_TILDE,
};
static const struct {
char c1, c2;
enum tokens tok;
} tokens_2[] = {
{ '|', '|', T_PIPEPIPE },
{ '&', '&', T_AMPAMP },
{ '=', '=', T_EQEQ },
{ '!', '=', T_BANGEQ },
{ '<', '=', T_LTEQ },
{ '>', '=', T_GTEQ },
{ '<', '<', T_LTLT },
{ '>', '>', T_GTGT },
};
static const unsigned num_tokens_2 = HOWMANY(tokens_2);
static const struct {
char c1;
enum tokens tok;
} tokens_1[] = {
{ '?', T_QUES },
{ ':', T_COLON },
{ '|', T_PIPE },
{ '^', T_CARET },
{ '&', T_AMP },
{ '<', T_LT },
{ '>', T_GT },
{ '+', T_PLUS },
{ '-', T_MINUS },
{ '*', T_STAR },
{ '/', T_SLASH },
{ '%', T_PCT },
{ '!', T_BANG },
{ '~', T_TILDE },
{ '(', T_LPAREN },
{ ')', T_RPAREN },
};
static const unsigned num_tokens_1 = HOWMANY(tokens_1);
struct token {
struct place place;
enum tokens tok;
int val;
};
DECLARRAY(token, static UNUSED);
DEFARRAY(token, static);
static struct tokenarray tokens;
static
struct token *
token_create(const struct place *p, enum tokens tok, int val)
{
struct token *t;
t = domalloc(sizeof(*t));
t->place = *p;
t->tok = tok;
t->val = val;
return t;
}
static
void
token_destroy(struct token *t)
{
dofree(t, sizeof(*t));
}
DESTROYALL_ARRAY(token, );
#ifdef DEBUG
static
void
printtokens(void)
{
unsigned i, num;
struct token *t;
fprintf(stderr, "tokens:");
num = tokenarray_num(&tokens);
for (i=0; i<num; i++) {
t = tokenarray_get(&tokens, i);
switch (t->tok) {
case T_EOF: fprintf(stderr, " <eof>"); break;
case T_VAL: fprintf(stderr, " %d", t->val); break;
case T_LPAREN: fprintf(stderr, " ("); break;
case T_RPAREN: fprintf(stderr, " )"); break;
case T_PIPEPIPE: fprintf(stderr, " ||"); break;
case T_AMPAMP: fprintf(stderr, " &&"); break;
case T_EQEQ: fprintf(stderr, " =="); break;
case T_BANGEQ: fprintf(stderr, " !="); break;
case T_LTEQ: fprintf(stderr, " <="); break;
case T_GTEQ: fprintf(stderr, " >="); break;
case T_LTLT: fprintf(stderr, " <<"); break;
case T_GTGT: fprintf(stderr, " >>"); break;
case T_QUES: fprintf(stderr, " ?"); break;
case T_COLON: fprintf(stderr, " :"); break;
case T_PIPE: fprintf(stderr, " |"); break;
case T_CARET: fprintf(stderr, " ^"); break;
case T_AMP: fprintf(stderr, " &"); break;
case T_LT: fprintf(stderr, " <"); break;
case T_GT: fprintf(stderr, " >"); break;
case T_PLUS: fprintf(stderr, " +"); break;
case T_MINUS: fprintf(stderr, " -"); break;
case T_STAR: fprintf(stderr, " *"); break;
case T_SLASH: fprintf(stderr, " /"); break;
case T_PCT: fprintf(stderr, " %%"); break;
case T_BANG: fprintf(stderr, " !"); break;
case T_TILDE: fprintf(stderr, " ~"); break;
}
}
fprintf(stderr, "\n");
}
#endif
static
bool
isuop(enum tokens tok)
{
switch (tok) {
case T_BANG:
case T_TILDE:
case T_MINUS:
case T_PLUS:
return true;
default:
break;
}
return false;
}
static
bool
isbop(enum tokens tok)
{
switch (tok) {
case T_EOF:
case T_VAL:
case T_LPAREN:
case T_RPAREN:
case T_COLON:
case T_QUES:
case T_BANG:
case T_TILDE:
return false;
default:
break;
}
return true;
}
static
bool
isop(enum tokens tok)
{
switch (tok) {
case T_EOF:
case T_VAL:
case T_LPAREN:
case T_RPAREN:
return false;
default:
break;
}
return true;
}
static
int
getprec(enum tokens tok)
{
switch (tok) {
case T_BANG: case T_TILDE: return -1;
case T_STAR: case T_SLASH: case T_PCT: return 0;
case T_PLUS: case T_MINUS: return 1;
case T_LTLT: case T_GTGT: return 2;
case T_LT: case T_LTEQ: case T_GT: case T_GTEQ: return 3;
case T_EQEQ: case T_BANGEQ: return 4;
case T_AMP: return 5;
case T_CARET: return 6;
case T_PIPE: return 7;
case T_AMPAMP: return 8;
case T_PIPEPIPE: return 9;
default: break;
}
return 10;
}
static
bool
looser(enum tokens t1, enum tokens t2)
{
return getprec(t1) >= getprec(t2);
}
static
int
eval_uop(enum tokens op, int val)
{
switch (op) {
case T_BANG: val = !val; break;
case T_TILDE: val = (int)~(unsigned)val; break;
case T_MINUS: val = -val; break;
case T_PLUS: break;
default: assert(0); break;
}
return val;
}
static
int
eval_bop(struct place *p, int lv, enum tokens op, int rv)
{
unsigned mask;
switch (op) {
case T_PIPEPIPE: return lv || rv;
case T_AMPAMP: return lv && rv;
case T_PIPE: return (int)((unsigned)lv | (unsigned)rv);
case T_CARET: return (int)((unsigned)lv ^ (unsigned)rv);
case T_AMP: return (int)((unsigned)lv & (unsigned)rv);
case T_EQEQ: return lv == rv;
case T_BANGEQ: return lv != rv;
case T_LT: return lv < rv;
case T_GT: return lv > rv;
case T_LTEQ: return lv <= rv;
case T_GTEQ: return lv >= rv;
case T_LTLT:
case T_GTGT:
if (rv < 0) {
complain(p, "Negative bit-shift");
complain_fail();
rv = 0;
}
if ((unsigned)rv >= CHAR_BIT * sizeof(unsigned)) {
complain(p, "Bit-shift farther than type width");
complain_fail();
rv = 0;
}
if (op == T_LTLT) {
return (int)((unsigned)lv << (unsigned)rv);
}
mask = ((unsigned)-1) << (CHAR_BIT * sizeof(unsigned) - rv);
lv = (int)(((unsigned)lv >> (unsigned)rv) | mask);
return lv;
case T_MINUS:
if (rv == INT_MIN) {
if (lv == INT_MIN) {
return 0;
}
lv--;
rv++;
}
rv = -rv;
/* FALLTHROUGH */
case T_PLUS:
if (rv > 0 && lv > (INT_MAX - rv)) {
complain(p, "Integer overflow");
complain_fail();
return INT_MAX;
}
if (rv < 0 && lv < (INT_MIN - rv)) {
complain(p, "Integer underflow");
complain_fail();
return INT_MIN;
}
return lv + rv;
case T_STAR:
if (rv == 0) {
return 0;
}
if (rv == 1) {
return lv;
}
if (rv == -1 && lv == INT_MIN) {
lv++;
lv = -lv;
if (lv == INT_MAX) {
complain(p, "Integer overflow");
complain_fail();
return INT_MAX;
}
lv++;
return lv;
}
if (lv == INT_MIN && rv < 0) {
complain(p, "Integer overflow");
complain_fail();
return INT_MAX;
}
if (lv == INT_MIN && rv > 0) {
complain(p, "Integer underflow");
complain_fail();
return INT_MIN;
}
if (rv < 0) {
rv = -rv;
lv = -lv;
}
if (lv > 0 && lv > INT_MAX / rv) {
complain(p, "Integer overflow");
complain_fail();
return INT_MAX;
}
if (lv < 0 && lv < INT_MIN / rv) {
complain(p, "Integer underflow");
complain_fail();
return INT_MIN;
}
return lv * rv;
case T_SLASH:
if (rv == 0) {
complain(p, "Division by zero");
complain_fail();
return 0;
}
return lv / rv;
case T_PCT:
if (rv == 0) {
complain(p, "Modulus by zero");
complain_fail();
return 0;
}
return lv % rv;
default: assert(0); break;
}
return 0;
}
static
void
tryreduce(void)
{
unsigned num;
struct token *t1, *t2, *t3, *t4, *t5, *t6;
while (1) {
#ifdef DEBUG
printtokens();
#endif
num = tokenarray_num(&tokens);
t1 = (num >= 1) ? tokenarray_get(&tokens, num-1) : NULL;
t2 = (num >= 2) ? tokenarray_get(&tokens, num-2) : NULL;
t3 = (num >= 3) ? tokenarray_get(&tokens, num-3) : NULL;
if (num >= 3 &&
t3->tok == T_LPAREN &&
t2->tok == T_VAL &&
t1->tok == T_RPAREN) {
/* (x) -> x */
t2->place = t3->place;
token_destroy(t1);
token_destroy(t3);
tokenarray_remove(&tokens, num-1);
tokenarray_remove(&tokens, num-3);
continue;
}
if (num >= 2 &&
(num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) &&
isuop(t2->tok) &&
t1->tok == T_VAL) {
/* unary operator */
t1->val = eval_uop(t2->tok, t1->val);
t1->place = t2->place;
token_destroy(t2);
tokenarray_remove(&tokens, num-2);
continue;
}
if (num >= 2 &&
(num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) &&
t2->tok != T_LPAREN && t2->tok != T_VAL &&
t1->tok == T_VAL) {
complain(&t2->place, "Invalid unary operator");
complain_fail();
token_destroy(t2);
tokenarray_remove(&tokens, num-2);
continue;
}
t4 = (num >= 4) ? tokenarray_get(&tokens, num-4) : NULL;
if (num >= 4 &&
t4->tok == T_VAL &&
isbop(t3->tok) &&
t2->tok == T_VAL) {
/* binary operator */
if (looser(t1->tok, t3->tok)) {
t4->val = eval_bop(&t3->place,
t4->val, t3->tok, t2->val);
token_destroy(t2);
token_destroy(t3);
tokenarray_remove(&tokens, num-2);
tokenarray_remove(&tokens, num-3);
continue;
}
break;
}
t5 = (num >= 5) ? tokenarray_get(&tokens, num-5) : NULL;
t6 = (num >= 6) ? tokenarray_get(&tokens, num-6) : NULL;
if (num >= 6 &&
t6->tok == T_VAL &&
t5->tok == T_QUES &&
t4->tok == T_VAL &&
t3->tok == T_COLON &&
t2->tok == T_VAL &&
!isop(t1->tok)) {
/* conditional expression */
t6->val = t6->val ? t4->val : t2->val;
token_destroy(t2);
token_destroy(t3);
token_destroy(t4);
token_destroy(t5);
tokenarray_remove(&tokens, num-2);
tokenarray_remove(&tokens, num-3);
tokenarray_remove(&tokens, num-4);
tokenarray_remove(&tokens, num-5);
continue;
}
if (num >= 2 &&
t2->tok == T_LPAREN &&
t1->tok == T_RPAREN) {
complain(&t1->place, "Value expected within ()");
complain_fail();
t1->tok = T_VAL;
t1->val = 0;
token_destroy(t1);
tokenarray_remove(&tokens, num-1);
continue;
}
if (num >= 2 &&
t2->tok == T_VAL &&
t1->tok == T_VAL) {
complain(&t1->place, "Operator expected");
complain_fail();
token_destroy(t1);
tokenarray_remove(&tokens, num-1);
continue;
}
if (num >= 2 &&
isop(t2->tok) &&
t1->tok == T_EOF) {
complain(&t1->place, "Value expected after operator");
complain_fail();
token_destroy(t2);
tokenarray_remove(&tokens, num-2);
continue;
}
if (num == 2 &&
t2->tok == T_VAL &&
t1->tok == T_RPAREN) {
complain(&t1->place, "Excess right parenthesis");
complain_fail();
token_destroy(t1);
tokenarray_remove(&tokens, num-1);
continue;
}
if (num == 3 &&
t3->tok == T_LPAREN &&
t2->tok == T_VAL &&
t1->tok == T_EOF) {
complain(&t1->place, "Unclosed left parenthesis");
complain_fail();
token_destroy(t3);
tokenarray_remove(&tokens, num-3);
continue;
}
if (num == 2 &&
t2->tok == T_VAL &&
t1->tok == T_EOF) {
/* accepting state */
break;
}
if (num >= 1 &&
t1->tok == T_EOF) {
/* any other configuration at eof is an error */
complain(&t1->place, "Parse error");
complain_fail();
break;
}
/* otherwise, wait for more input */
break;
}
}
static
void
token(struct place *p, enum tokens tok, int val)
{
struct token *t;
t = token_create(p, tok, val);
tokenarray_add(&tokens, t, NULL);
tryreduce();
}
static
int
wordval(struct place *p, char *word)
{
unsigned long val;
char *t;
if (word[0] >= '0' && word[0] <= '9') {
errno = 0;
val = strtoul(word, &t, 0);
if (errno) {
complain(p, "Invalid integer constant");
complain_fail();
return 0;
}
while (*t == 'U' || *t == 'L') {
t++;
}
if (*t != '\0') {
complain(p, "Trailing garbage after integer constant");
complain_fail();
return 0;
}
if (val > INT_MAX) {
complain(p, "Integer constant too large");
complain_fail();
return INT_MAX;
}
return val;
}
/* if it's a symbol, warn and substitute 0. */
if (warns.undef) {
complain(p, "Warning: value of undefined symbol %s is 0",
word);
if (mode.werror) {
complain_fail();
}
}
return 0;
}
static
bool
check_word(struct place *p, char *expr, size_t pos, size_t *len_ret)
{
size_t len;
int val;
char tmp;
if (!strchr(alnum, expr[pos])) {
return false;
}
len = strspn(expr + pos, alnum);
tmp = expr[pos + len];
expr[pos + len] = '\0';
val = wordval(p, expr + pos);
expr[pos + len] = tmp;
token(p, T_VAL, val);
*len_ret = len;
return true;
}
static
bool
check_tokens_2(struct place *p, char *expr, size_t pos)
{
unsigned i;
for (i=0; i<num_tokens_2; i++) {
if (expr[pos] == tokens_2[i].c1 &&
expr[pos+1] == tokens_2[i].c2) {
token(p, tokens_2[i].tok, 0);
return true;
}
}
return false;
}
static
bool
check_tokens_1(struct place *p, char *expr, size_t pos)
{
unsigned i;
for (i=0; i<num_tokens_1; i++) {
if (expr[pos] == tokens_1[i].c1) {
token(p, tokens_1[i].tok, 0);
return true;
}
}
return false;
}
static
void
tokenize(struct place *p, char *expr)
{
size_t pos, len;
pos = 0;
while (expr[pos] != '\0') {
len = strspn(expr+pos, ws);
pos += len;
p->column += len;
/* trailing whitespace is supposed to have been pruned */
assert(expr[pos] != '\0');
if (check_word(p, expr, pos, &len)) {
pos += len;
p->column += len;
continue;
}
if (check_tokens_2(p, expr, pos)) {
pos += 2;
p->column += 2;
continue;
}
if (check_tokens_1(p, expr, pos)) {
pos++;
p->column++;
continue;
}
complain(p, "Invalid character %u in #if-expression",
(unsigned char)expr[pos]);
complain_fail();
pos++;
p->column++;
}
token(p, T_EOF, 0);
}
bool
eval(struct place *p, char *expr)
{
struct token *t1, *t2;
unsigned num;
bool result;
#ifdef DEBUG
fprintf(stderr, "eval: %s\n", expr);
#endif
tokenarray_init(&tokens);
tokenize(p, expr);
result = false;
num = tokenarray_num(&tokens);
if (num == 2) {
t1 = tokenarray_get(&tokens, num-1);
t2 = tokenarray_get(&tokens, num-2);
if (t2->tok == T_VAL &&
t1->tok == T_EOF) {
result = t2->val != 0;
}
}
tokenarray_destroyall(&tokens);
tokenarray_cleanup(&tokens);
return result;
}

32
cde/util/tradcpp/eval.h Normal file
View file

@ -0,0 +1,32 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
bool eval(struct place *p, char *expr);

420
cde/util/tradcpp/files.c Normal file
View file

@ -0,0 +1,420 @@
/*-
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "array.h"
#include "mode.h"
#include "place.h"
#include "files.h"
#include "directive.h"
struct incdir {
const char *name;
bool issystem;
};
DECLARRAY(incdir, static UNUSED);
DEFARRAY(incdir, static);
static struct incdirarray quotepath, bracketpath;
////////////////////////////////////////////////////////////
// management
static
struct incdir *
incdir_create(const char *name, bool issystem)
{
struct incdir *id;
id = domalloc(sizeof(*id));
id->name = name;
id->issystem = issystem;
return id;
}
static
void
incdir_destroy(struct incdir *id)
{
dofree(id, sizeof(*id));
}
void
files_init(void)
{
incdirarray_init(&quotepath);
incdirarray_init(&bracketpath);
}
DESTROYALL_ARRAY(incdir, );
void
files_cleanup(void)
{
incdirarray_destroyall(&quotepath);
incdirarray_cleanup(&quotepath);
incdirarray_destroyall(&bracketpath);
incdirarray_cleanup(&bracketpath);
}
////////////////////////////////////////////////////////////
// path setup
void
files_addquotepath(const char *dir, bool issystem)
{
struct incdir *id;
id = incdir_create(dir, issystem);
incdirarray_add(&quotepath, id, NULL);
}
void
files_addbracketpath(const char *dir, bool issystem)
{
struct incdir *id;
id = incdir_create(dir, issystem);
incdirarray_add(&bracketpath, id, NULL);
}
////////////////////////////////////////////////////////////
// parsing
/*
* Find the end of the logical line. End of line characters that are
* commented out do not count.
*/
static
size_t
findeol(const char *buf, size_t start, size_t limit)
{
size_t i;
int incomment = 0;
bool inquote = false;
char quote = '\0';
for (i=start; i<limit; i++) {
if (incomment) {
if (i+1 < limit && buf[i] == '*' && buf[i+1] == '/') {
i++;
incomment = 0;
}
} else if (!inquote && i+1 < limit &&
buf[i] == '/' && buf[i+1] == '*') {
i++;
incomment = 1;
} else if (i+1 < limit &&
buf[i] == '\\' && buf[i+1] != '\n') {
i++;
} else if (!inquote && (buf[i] == '"' || buf[i] == '\'')) {
inquote = true;
quote = buf[i];
} else if (inquote && buf[i] == quote) {
inquote = false;
} else if (buf[i] == '\n') {
return i;
}
}
return limit;
}
static
unsigned
countnls(const char *buf, size_t start, size_t limit)
{
size_t i;
unsigned count = 0;
for (i=start; i<limit; i++) {
if (buf[i] == '\n') {
count++;
}
}
return count;
}
static
void
file_read(const struct placefile *pf, int fd, const char *name, bool toplevel)
{
struct place linestartplace, nextlinestartplace, ptmp;
size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp;
ssize_t result;
bool ateof = false;
char *buf;
place_setfilestart(&linestartplace, pf);
nextlinestartplace = linestartplace;
bufmax = 128;
bufend = 0;
linestart = 0;
lineend = 0;
buf = domalloc(bufmax);
while (1) {
if (lineend >= bufend) {
/* do not have a whole line in the buffer; read more */
assert(bufend >= linestart);
if (linestart > 0 && bufend > linestart) {
/* slide to beginning of buffer */
memmove(buf, buf+linestart, bufend-linestart);
bufend -= linestart;
lineend -= linestart;
linestart = 0;
}
if (bufend >= bufmax) {
/* need bigger buffer */
buf = dorealloc(buf, bufmax, bufmax*2);
bufmax = bufmax*2;
}
if (ateof) {
/* don't read again, in case it's a socket */
result = 0;
} else {
result = read(fd, buf+bufend, bufmax - bufend);
}
if (result == -1) {
/* read error */
complain(NULL, "%s: %s",
name, strerror(errno));
complain_fail();
} else if (result == 0 && bufend == linestart) {
/* eof */
ateof = true;
break;
} else if (result == 0) {
/* eof in middle of line */
ateof = true;
ptmp = linestartplace;
ptmp.column += bufend - linestart;
complain(&ptmp, "No newline at end of file");
if (mode.werror) {
complain_fail();
}
assert(bufend < bufmax);
lineend = bufend++;
buf[lineend] = '\n';
} else {
bufend += (size_t)result;
lineend = findeol(buf, linestart, bufend);
}
/* loop in case we still don't have a whole line */
continue;
}
/* have a line */
assert(buf[lineend] == '\n');
buf[lineend] = '\0';
nextlinestart = lineend+1;
nextlinestartplace.line++;
/* check for CR/NL */
if (lineend > 0 && buf[lineend-1] == '\r') {
buf[lineend-1] = '\0';
lineend--;
}
/* check for continuation line */
if (lineend > 0 && buf[lineend-1]=='\\') {
lineend--;
tmp = nextlinestart - lineend;
if (bufend > nextlinestart) {
memmove(buf+lineend, buf+nextlinestart,
bufend - nextlinestart);
}
bufend -= tmp;
nextlinestart -= tmp;
lineend = findeol(buf, linestart, bufend);
/* might not have a whole line, so loop */
continue;
}
/* line now goes from linestart to lineend */
assert(buf[lineend] == '\0');
/* count how many commented-out newlines we swallowed */
nextlinestartplace.line += countnls(buf, linestart, lineend);
/* if the line isn't empty, process it */
if (lineend > linestart) {
directive_gotline(&linestartplace,
buf+linestart, lineend-linestart);
}
linestart = nextlinestart;
lineend = findeol(buf, linestart, bufend);
linestartplace = nextlinestartplace;
}
if (toplevel) {
directive_goteof(&linestartplace);
}
dofree(buf, bufmax);
}
////////////////////////////////////////////////////////////
// path search
static
char *
mkfilename(struct place *place, const char *dir, const char *file)
{
size_t dlen, flen, rlen;
char *ret;
bool needslash = false;
if (dir == NULL) {
dir = place_getparsedir(place);
}
dlen = strlen(dir);
flen = strlen(file);
if (dlen > 0 && dir[dlen-1] != '/') {
needslash = true;
}
rlen = dlen + (needslash ? 1 : 0) + flen;
ret = domalloc(rlen + 1);
strcpy(ret, dir);
if (needslash) {
strcat(ret, "/");
}
strcat(ret, file);
return ret;
}
static
int
file_tryopen(const char *file)
{
int fd;
/* XXX check for non-regular files */
fd = open(file, O_RDONLY);
if (fd < 0) {
if (errno != ENOENT && errno != ENOTDIR) {
complain(NULL, "%s: %s", file, strerror(errno));
}
return -1;
}
return fd;
}
static
void
file_search(struct place *place, struct incdirarray *path, const char *name)
{
unsigned i, num;
struct incdir *id;
const struct placefile *pf;
char *file;
int fd;
assert(place != NULL);
if (name[0] == '/') {
fd = file_tryopen(name);
if (fd >= 0) {
pf = place_addfile(place, name, true);
file_read(pf, fd, name, false);
close(fd);
return;
}
} else {
num = incdirarray_num(path);
for (i=0; i<num; i++) {
id = incdirarray_get(path, i);
file = mkfilename(place, id->name, name);
fd = file_tryopen(file);
if (fd >= 0) {
pf = place_addfile(place, file, id->issystem);
file_read(pf, fd, file, false);
dostrfree(file);
close(fd);
return;
}
dostrfree(file);
}
}
complain(place, "Include file %s not found", name);
complain_fail();
}
void
file_readquote(struct place *place, const char *name)
{
file_search(place, &quotepath, name);
}
void
file_readbracket(struct place *place, const char *name)
{
file_search(place, &bracketpath, name);
}
void
file_readabsolute(struct place *place, const char *name)
{
const struct placefile *pf;
int fd;
assert(place != NULL);
if (name == NULL) {
fd = STDIN_FILENO;
pf = place_addfile(place, "<standard-input>", false);
} else {
fd = file_tryopen(name);
if (fd < 0) {
complain(NULL, "%s: %s", name, strerror(errno));
die();
}
pf = place_addfile(place, name, false);
}
file_read(pf, fd, name, true);
if (name != NULL) {
close(fd);
}
}

40
cde/util/tradcpp/files.h Normal file
View file

@ -0,0 +1,40 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
struct place;
void files_init(void);
void files_cleanup(void);
void files_addquotepath(const char *dir, bool issystem);
void files_addbracketpath(const char *dir, bool issystem);
void file_readquote(struct place *, const char *name);
void file_readbracket(struct place *, const char *name);
void file_readabsolute(struct place *, const char *name);

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2009 David A. Holland.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Author nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__)
/* gcc's non-C99 inline semantics */
#define C99INLINE extern inline
#elif defined(__STDC__) && __STDC_VERSION__ >= 199901L
/* C99 */
#define C99INLINE inline
#else
/* something else; static inline is safest */
#define C99INLINE static inline
#endif

1202
cde/util/tradcpp/macro.c Normal file

File diff suppressed because it is too large Load diff

49
cde/util/tradcpp/macro.h Normal file
View file

@ -0,0 +1,49 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
#include <stddef.h>
struct place;
void macros_init(void);
void macros_cleanup(void);
void macro_define_plain(struct place *, const char *macro,
struct place *, const char *expansion);
void macro_define_params(struct place *, const char *macro,
struct place *, const char *params,
struct place *, const char *expansion);
void macro_undef(const char *macro);
bool macro_isdefined(const char *macro);
char *macroexpand(struct place *, char *buf, size_t len, bool honordefined);
void macro_sendline(struct place *, char *buf, size_t len);
void macro_sendeof(struct place *);

1090
cde/util/tradcpp/main.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
gcc -o tradcpp main.c files.c directive.c eval.c macro.c output.c place.c array.c utils.c

65
cde/util/tradcpp/mode.h Normal file
View file

@ -0,0 +1,65 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
struct mode {
bool werror;
bool input_allow_dollars;
unsigned input_tabstop;
bool do_stdinc;
bool do_stddef;
bool do_output;
bool output_linenumbers;
bool output_retain_comments;
const char *output_file;
bool do_depend;
bool depend_report_system;
bool depend_assume_generated;
bool depend_issue_fakerules;
bool depend_quote_target;
const char *depend_target;
const char *depend_file;
bool do_macrolist;
bool macrolist_include_stddef;
bool macrolist_include_expansions;
bool do_trace;
bool trace_namesonly;
bool trace_indented;
};
struct warns {
bool endiflabels;
bool nestcomment;
bool undef;
bool unused;
};
extern struct mode mode;
extern struct warns warns;

193
cde/util/tradcpp/output.c Normal file
View file

@ -0,0 +1,193 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "utils.h"
#include "mode.h"
#include "place.h"
#include "output.h"
static int outputfd = -1;
static bool incomment = false;
static char *linebuf;
static size_t linebufpos, linebufmax;
static struct place linebufplace;
static
void
output_open(void)
{
if (mode.output_file == NULL) {
outputfd = STDOUT_FILENO;
} else {
outputfd = open(mode.output_file, O_WRONLY|O_CREAT|O_TRUNC,
0664);
if (outputfd < 0) {
complain(NULL, "%s: %s",
mode.output_file, strerror(errno));
die();
}
}
}
static
void
dowrite(const char *buf, size_t len)
{
size_t done;
ssize_t result;
static unsigned write_errors = 0;
if (!mode.do_output) {
return;
}
if (outputfd < 0) {
output_open();
}
done = 0;
while (done < len) {
result = write(outputfd, buf+done, len-done);
if (result == -1) {
complain(NULL, "%s: write: %s",
mode.output_file, strerror(errno));
complain_failed();
write_errors++;
if (write_errors > 5) {
complain(NULL, "%s: giving up",
mode.output_file);
die();
}
/* XXX is this really a good idea? */
sleep(1);
}
done += (size_t)result;
}
}
static
void
filter_output(const char *buf, size_t len)
{
size_t pos, start;
bool inesc = false;
bool inquote = false;
char quote = '\0';
start = 0;
for (pos = 0; pos < len - 1; pos++) {
if (!inquote && buf[pos] == '/' && buf[pos+1] == '*') {
if (!incomment) {
if (pos > start) {
dowrite(buf + start, pos - start);
}
start = pos;
pos += 2;
incomment = true;
/* cancel out the loop's pos++ */
pos--;
continue;
}
} else if (buf[pos] == '*' && buf[pos+1] == '/') {
if (incomment) {
pos += 2;
if (mode.output_retain_comments) {
dowrite(buf + start, pos - start);
}
start = pos;
incomment = false;
/* cancel out the loop's pos++ */
pos--;
continue;
}
}
if (incomment) {
/* nothing */
} else if (inesc) {
inesc = false;
} else if (buf[pos] == '\\') {
inesc = true;
} else if (!inquote && (buf[pos] == '"' || buf[pos] == '\'')) {
inquote = true;
quote = buf[pos];
} else if (inquote && buf[pos] == quote) {
inquote = false;
}
}
pos++;
if (pos > start) {
if (!incomment || mode.output_retain_comments) {
dowrite(buf + start, pos - start);
}
}
}
void
output(const struct place *p, const char *buf, size_t len)
{
size_t oldmax;
if (linebufpos + len > linebufmax) {
oldmax = linebufmax;
if (linebufmax == 0) {
linebufmax = 64;
}
while (linebufpos + len > linebufmax) {
linebufmax *= 2;
}
linebuf = dorealloc(linebuf, oldmax, linebufmax);
}
if (linebufpos == 0) {
linebufplace = *p;
}
memcpy(linebuf + linebufpos, buf, len);
linebufpos += len;
if (len == 1 && buf[0] == '\n') {
filter_output(linebuf, linebufpos);
linebufpos = 0;
}
}
void
output_eof(void)
{
if (mode.output_file != NULL && outputfd >= 0) {
close(outputfd);
}
outputfd = -1;
}

31
cde/util/tradcpp/output.h Normal file
View file

@ -0,0 +1,31 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
void output(const struct place *p, const char *buf, size_t len);
void output_eof(void);

241
cde/util/tradcpp/place.c Normal file
View file

@ -0,0 +1,241 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utils.h"
#include "array.h"
#include "place.h"
struct placefile {
struct place includedfrom;
char *dir;
char *name;
int depth;
bool fromsystemdir;
};
DECLARRAY(placefile, static UNUSED);
DEFARRAY(placefile, static);
static struct placefilearray placefiles;
static bool overall_failure;
static const char *myprogname;
////////////////////////////////////////////////////////////
// seenfiles
static
struct placefile *
placefile_create(const struct place *from, const char *name,
bool fromsystemdir)
{
struct placefile *pf;
const char *s;
size_t len;
pf = domalloc(sizeof(*pf));
pf->includedfrom = *from;
s = strrchr(name, '/');
len = (s == NULL) ? 0 : s - name;
pf->dir = dostrndup(name, len);
pf->name = dostrdup(name);
pf->fromsystemdir = fromsystemdir;
if (from->file != NULL) {
pf->depth = from->file->depth + 1;
} else {
pf->depth = 1;
}
return pf;
}
static
void
placefile_destroy(struct placefile *pf)
{
dostrfree(pf->name);
dofree(pf, sizeof(*pf));
}
DESTROYALL_ARRAY(placefile, );
const char *
place_getparsedir(const struct place *place)
{
if (place->file == NULL) {
return ".";
}
return place->file->dir;
}
const struct placefile *
place_addfile(const struct place *place, const char *file, bool issystem)
{
struct placefile *pf;
pf = placefile_create(place, file, issystem);
placefilearray_add(&placefiles, pf, NULL);
if (pf->depth > 120) {
complain(place, "Maximum include nesting depth exceeded");
die();
}
return pf;
}
////////////////////////////////////////////////////////////
// places
void
place_setnowhere(struct place *p)
{
p->type = P_NOWHERE;
p->file = NULL;
p->line = 0;
p->column = 0;
}
void
place_setbuiltin(struct place *p, unsigned num)
{
p->type = P_BUILTIN;
p->file = NULL;
p->line = num;
p->column = 1;
}
void
place_setcommandline(struct place *p, unsigned line, unsigned column)
{
p->type = P_COMMANDLINE;
p->file = NULL;
p->line = line;
p->column = column;
}
void
place_setfilestart(struct place *p, const struct placefile *pf)
{
p->type = P_FILE;
p->file = pf;
p->line = 1;
p->column = 1;
}
static
const char *
place_getname(const struct place *p)
{
switch (p->type) {
case P_NOWHERE: return "<nowhere>";
case P_BUILTIN: return "<built-in>";
case P_COMMANDLINE: return "<command-line>";
case P_FILE: return p->file->name;
}
assert(0);
return NULL;
}
static
void
place_printfrom(const struct place *p)
{
const struct place *from;
if (p->file == NULL) {
return;
}
from = &p->file->includedfrom;
if (from->type != P_NOWHERE) {
place_printfrom(from);
fprintf(stderr, "In file included from %s:%u:%u:\n",
place_getname(from), from->line, from->column);
}
}
////////////////////////////////////////////////////////////
// complaints
void
complain_init(const char *pn)
{
myprogname = pn;
}
void
complain(const struct place *p, const char *fmt, ...)
{
va_list ap;
if (p != NULL) {
place_printfrom(p);
fprintf(stderr, "%s:%u:%u: ", place_getname(p),
p->line, p->column);
} else {
fprintf(stderr, "%s: ", myprogname);
}
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
void
complain_fail(void)
{
overall_failure = true;
}
bool
complain_failed(void)
{
return overall_failure;
}
////////////////////////////////////////////////////////////
// module init and cleanup
void
place_init(void)
{
placefilearray_init(&placefiles);
}
void
place_cleanup(void)
{
placefilearray_destroyall(&placefiles);
placefilearray_cleanup(&placefiles);
}

56
cde/util/tradcpp/place.h Normal file
View file

@ -0,0 +1,56 @@
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
enum places {
P_NOWHERE,
P_BUILTIN,
P_COMMANDLINE,
P_FILE,
};
struct place {
enum places type;
const struct placefile *file;
unsigned line;
unsigned column;
};
void place_init(void);
void place_cleanup(void);
void place_setnowhere(struct place *p);
void place_setbuiltin(struct place *p, unsigned num);
void place_setcommandline(struct place *p, unsigned word, unsigned column);
void place_setfilestart(struct place *p, const struct placefile *pf);
const char *place_getparsedir(const struct place *incplace);
const struct placefile *place_addfile(const struct place *incplace,
const char *name, bool fromsystemdir);

View file

@ -0,0 +1 @@
hello

View file

@ -0,0 +1 @@
glop.

View file

@ -0,0 +1 @@
glop.

View file

@ -0,0 +1,2 @@
#define glop flop
glop

View file

@ -0,0 +1 @@
flop

View file

@ -0,0 +1,2 @@
#define glop(x) flop x
glop(boo)

View file

@ -0,0 +1 @@
flop boo

View file

@ -0,0 +1,2 @@
#define string(x) "x"
string(abc)

View file

@ -0,0 +1 @@
"abc"

View file

@ -0,0 +1,2 @@
#define concat(a, b) a/**/b
concat(abc,def)

View file

@ -0,0 +1 @@
abcdef

View file

@ -0,0 +1,2 @@
/*glop*/

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,3 @@
/*
* gloop
*/

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,41 @@
/*#include <stdio.h>*/
int d =
#if 2 > 1 ? 0 : 0 ? 1 : 1
1
#else
0
#endif
;
int e =
#if (2 > 1 ? 0 : 0) ? 1 : 1
1
#else
0
#endif
;
int f =
#if 2 > 1 ? 0 : (0 ? 1 : 1)
1
#else
0
#endif
;
int
main()
{
int a, b, c;
a = 2 > 1 ? 0 : 0 ? 1 : 1;
b = (2 > 1 ? 0 : 0) ? 1 : 1;
c = 2 > 1 ? 0 : (0 ? 1 : 1);
printf("%d %d %d\n", a, b, c);
printf("%d %d %d\n", d, e, f);
return 0;
}

View file

@ -0,0 +1,21 @@
int d =
0
;
int e =
1
;
int f =
0
;
int
main()
{
int a, b, c;
a = 2 > 1 ? 0 : 0 ? 1 : 1;
b = (2 > 1 ? 0 : 0) ? 1 : 1;
c = 2 > 1 ? 0 : (0 ? 1 : 1);
printf("%d %d %d\n", a, b, c);
printf("%d %d %d\n", d, e, f);
return 0;
}

View file

@ -0,0 +1,6 @@
#define STOP */
#define START /*
/*
* blah blah blah STOP fnord START goop moop
*/

View file

View file

@ -0,0 +1,3 @@
#define mac(r)o
mac(3)
mac()

View file

@ -0,0 +1,2 @@
o
o

View file

@ -0,0 +1,2 @@
#define BOO BOO
BOO

View file

@ -0,0 +1 @@
BOO

View file

@ -0,0 +1,2 @@
#define BOO(yah) BOO(yah)
BOO(yah)

View file

@ -0,0 +1 @@
BOO(yah)

View file

@ -0,0 +1,4 @@
/*
#define FOO BAR
*/
FOO

View file

@ -0,0 +1,2 @@
FOO

View file

@ -0,0 +1,4 @@
/*
#define FOO BAR */
FOO
FOO

View file

@ -0,0 +1,3 @@
FOO
FOO

View file

@ -0,0 +1,3 @@
#define FOO /* BAR */ BAZ
FOO
FOO

View file

@ -0,0 +1,2 @@
BAZ
BAZ

View file

@ -0,0 +1,11 @@
#define a() x
a()
a ()
#define b(p) p
x/**/b(1)/**/x
x/**/b (1)/**/x
x/**/b()/**/x
#define c(p,q) p/**/q
x/**/c(1,2)/**/x
x/**/c(1)/**/x
x/**/c()/**/x

View file

@ -0,0 +1,11 @@
x
x
x1x
x1x
xx
x12x
t16.c:10:1: Wrong number of arguments for macro c; found 1, expected 2
x1x
t16.c:11:1: Wrong number of arguments for macro c; found 0, expected 2
xx
FAILED

View file

@ -0,0 +1,2 @@
#define file "subdir/test.h"
#include file

View file

@ -0,0 +1 @@
hello

View file

@ -0,0 +1,2 @@
#if FOO /* ignore me */
#endif

View file

View file

@ -0,0 +1,3 @@
#define foo /* comment continues
into the next line */ baz
baz

View file

@ -0,0 +1 @@
baz

View file

@ -0,0 +1 @@
#undef foo /* blah */

View file

View file

@ -0,0 +1,3 @@
# define FOO BAR
#undef FOO /* would be wrong */
FOO

View file

@ -0,0 +1,2 @@
#undef BAR
BAR

View file

@ -0,0 +1,2 @@
pa/*
*/ste

View file

@ -0,0 +1 @@
paste

View file

@ -0,0 +1,8 @@
/*
fnord1
/*
fnord2
*/
foo
*/
bar

View file

@ -0,0 +1,4 @@
foo
*/
bar

View file

@ -0,0 +1,67 @@
#if 0
wrong
#endif
#if 1
right
#endif
#if -1
right
#endif
#if 0 + 0
wrong
#endif
#if 1 + 1
right
#endif
#if 1 - 1
wrong
#endif
#if -1 + 1
wrong
#endif
#if 3 - 2 - 1
wrong
#endif
#if 3 * 2 - 6
wrong
#endif
#if 6 - 2 * 3
wrong
#endif
#if 3 - 3 && 1
wrong
#endif
#if 3 - 3 || 0
wrong
#endif
#if 1 && 0
wrong
#endif
#if 0 && 1
wrong
#endif
#if 1 || 0
right
#endif
#if 0 || 1
right
#endif
#if (0 || 1) && (0 || 0)
wrong
#endif

View file

@ -0,0 +1,5 @@
right
right
right
right
right

View file

@ -0,0 +1,4 @@
#define FOO foo /*
#undef FOO
#define FOO bar */
FOO

View file

@ -0,0 +1 @@
foo

View file

@ -0,0 +1,4 @@
#define FOO foo
FOO
"FOO"
'FOO'

View file

@ -0,0 +1,3 @@
foo
"FOO"
'FOO'

View file

@ -0,0 +1,29 @@
1.
#define A(a) a
A();
2.
#define B(a, b) (a,b)
B(a, );
B(, b);
B( , );
B(a,);
B(,b);
B(,);
3.
#define C(a, b, c) (a,b,c)
C(a, b, );
C(a, , c);
C(, , c);
C(a, , );
C(, b, );
C(, , c);
C(, , )
C(a,b,);
C(a,,c);
C(,,c);
C(a,,);
C(,b,);
C(,,c);
C(,,)

View file

@ -0,0 +1,24 @@
1.
;
2.
(a, );
(, b);
( , );
(a,);
(,b);
(,);
3.
(a, b, );
(a, , c);
(, , c);
(a, , );
(, b, );
(, , c);
(, , )
(a,b,);
(a,,c);
(,,c);
(a,,);
(,b,);
(,,c);
(,,)

View file

@ -0,0 +1,53 @@
#if 1
. right
# if 1
.. right
# elif 1
.. wrong
# elif 0
.. wrong
# else
.. wrong
# endif
#elif 1
. wrong
# if 1
.. wrong
# elif 1
.. wrong
# elif 0
.. wrong
# else
.. wrong
# endif
#elif 0
. wrong
# if 1
.. wrong
# elif 1
.. wrong
# elif 0
.. wrong
# else
.. wrong
# endif
#else
. wrong
# if 1
.. wrong
# elif 1
.. wrong
# elif 0
.. wrong
# else
.. wrong
# endif
#endif

View file

@ -0,0 +1,2 @@
. right
.. right

View file

@ -0,0 +1,4 @@
#if 0
# if this is a syntax error
# endif
#endif

View file

View file

@ -0,0 +1,2 @@
#define x(a,b,c) a;b;c;
x((,),x,",")

View file

@ -0,0 +1 @@
(,);x;",";

View file

@ -0,0 +1,6 @@
this line 'has /* no' comment */ in it
#define BELCH(x) 'x'
"BELCH(123)": BELCH(123)
'BELCH(123)': BELCH(123)

View file

@ -0,0 +1,3 @@
this line 'has /* no' comment */ in it
"BELCH(123)": '123'
'BELCH(123)': '123'

View file

@ -0,0 +1,21 @@
#define foo(x) "x"
#define bar(x) 'x'
#define baz frob
foo(3)
bar(3)
foo(baz)
bar(baz)
"baz"
'baz'
"foo(baz)"
"bar(baz)"
#define foo2(x) foo(x)
#define bar2(x) bar(x)
foo2(baz)
bar2(baz)
#define foo3(x) foo2(x)
#define bar3(x) bar2(x)
foo3(baz)
bar3(baz)

View file

@ -0,0 +1,12 @@
"3"
'3'
"baz"
'baz'
"baz"
'baz'
"foo(baz)"
"bar(baz)"
"baz"
'baz'
"baz"
'baz'

View file

@ -0,0 +1,6 @@
/* make sure that R gets defined and doesn't end up part of a string */
#define Q "
#define R r
#define S "
R
Q

View file

@ -0,0 +1,3 @@
r
"

View file

@ -0,0 +1,5 @@
#define Q "
#define FOO foo
Q FOO Q

View file

@ -0,0 +1 @@
" foo "

View file

@ -0,0 +1,6 @@
#define Q "
#define FOO foo
Q FOO Q 'I like "FOO" and "BAR"'

View file

@ -0,0 +1 @@
" foo " 'I like "FOO" and "BAR"'

View file

@ -0,0 +1,7 @@
#define C(x) //**/* x */**//
C(3)
C(abc /* def */ ghi)
#define D(x) ///**/**/**///**/* x */**///**/**/**///
D(3)
D(abc /* def */ ghi)

View file

@ -0,0 +1,4 @@
/* 3 */
/* abc ghi */
//**/* 3 */**//
//**/* abc ghi */**//

View file

@ -0,0 +1,19 @@
#define BC //**/*
#define EC */**//
BC
comment?
EC
BC comment? EC
#define FOO(x) x
FOO(abc BC def EC ghi)
#define BAR(x, y) x y
BAR(abc BC def, ghi EC jkl)
BC
#define BAZ baz
EC
BAZ

View file

@ -0,0 +1,9 @@
/*
comment?
*/
/* comment? */
abc /* def */ ghi
abc /* def ghi */ jkl
/*
*/
baz

Some files were not shown because too many files have changed in this diff Show more