1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-18 07:13:36 +02:00

Add tradcpp 0.4, a standalone traditional whitespace preserving cpp

by David A. Holland of NetBSD.
This commit is contained in:
jsg
2014-07-30 16:33:11 +00:00
parent 4f194ec8d9
commit a9b3ff1afb
23 changed files with 6150 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
PROG= tradcpp
SRCS= main.c \
files.c directive.c eval.c macro.c output.c \
place.c array.c utils.c
.include <bsd.prog.mk>
+115
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
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
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
+626
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;
}
+39
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
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
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
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
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);
+39
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
File diff suppressed because it is too large Load Diff
+49
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 *);
File diff suppressed because it is too large Load Diff
+65
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
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
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
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
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);
+353
View File
@@ -0,0 +1,353 @@
.\"
.\" Copyright (c) 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.
.\"
.Dd June 11, 2013
.Dt TRADCPP 1
.Os
.Sh NAME
.Nm tradcpp
.Nd traditional (K&R-style) C macro preprocessor
.Sh SYNOPSIS
.Nm tradcpp
.Op Fl options
.Op Ar input-file Op Ar output-file
.Sh DESCRIPTION
The
.Nm
command provides a traditional K&R-style C macro preprocessor.
It is intended to be suitable for historical Unix uses of the
preprocessor, such as
.Xr imake 1 ,
particularly those that depend on preservation of whitespace.
.Pp
The chief ways in which traditional cpp differs from
Standard C are:
.Bl -bullet -offset indent
.It
Macro arguments are expanded within quoted strings.
There is no stringize operator.
.It
There is no token pasting operator; tokens can be concatenated by
placing comments between them.
This process is also not limited to valid C language tokens.
.It
Whitespace is preserved, and in particular tabs are not expanded into
spaces.
Furthermore, additional whitespace is not injected.
.El
.Sh OPTIONS
.Nm
has many options, many of which are defined for compatibility with
.Xr gcc 1
or other compilers.
Many of the options are not yet implemented.
.\" The option lists have been sorted in what I hope is a sensible
.\" order. Please don't arbitrarily alphabetize them.
.Ss Common Options
.Bl -tag -width bubblebabble
.It Fl C
Retain comments in output.
.It Fl Dmacro[=expansion]
Provide a definition for the named macro.
If no expansion is provided, the value
.Dq 1
is used.
Note that like many Unix compilers,
.Nm
does not accept a space between the
.Dq D
and the macro name.
.It Fl Ipath
Add the specified path to the main list of include directories.
Note that like many Unix compilers,
.Nm
does not accept a space between the
.Dq I
and the directory name.
.It Fl nostdinc
Do not search the standard system include directories.
.It Fl P
Suppress line number information in the output.
Currently line number information is not generated at all and this
option has no effect.
.It Fl Umacro
Remove any existing defintion for the named macro.
Note that like many Unix compilers,
.Nm
does not accept a space between the
.Dq U
and the macro name.
.It Fl undef
Remove all predefined macros.
.El
.Ss Warning Options
Warning options can be disabled or enabled by inserting, or not, the
string
.Dq no-
between the
.Dq W
and the warning name.
Herein the
.Dq Fl Wno-
form is shown for options that are enabled by default.
.Bl -tag -width bubblebabble
.It Fl Wall
Turn on all warnings.
The option
.Fl Wno-all
disables only the warnings that are disabled by default.
.It Fl w
Turn off all warnings.
.It Fl Werror
Make warnings into fatal errors.
.It Fl Wcomment
Warn about nested comments.
.It Fl Wno-endif-labels
Don't warn about symbols attached to #endif directives.
(The warning is currently not implemented.)
.It Fl Wundef
Warn about undefined symbols appearing in #if and #elif expressions.
.It Fl Wunused-macros
Warn about macros that are defined and never used.
Not implemented.
.El
.Ss Depend Options
.Bl -tag -width bubblebabble
.It Fl M
Generate dependency information for
.Xr make 1
on the standard output, instead of preprocessing.
Not implemented.
.It Fl MD
Like
.Fl M
but skip system headers.
Not implemented.
.It Fl MM
Like
.Fl M
but write the dependency information to a file named after the input
file with extension
.Pa \.d
and preprocess normally to standard output.
Not implemented.
.It Fl MMD
Like
.Fl MM
but skip system headers.
Not implemented.
.It Fl MF Ar file
Send dependency output to the named file instead of the default
location.
Not implemented.
.It Fl MG
When generating dependency information, assume that missing files are
generated instead of failing.
Not implemented.
.It Fl MP
Issue dummy rules for all include files.
This prevents
.Xr make 1
from choking if an include file is removed.
Not implemented.
.It Fl MQ Ar target
Same as
.Fl MT
except that any
.Xr make 1
metacharacters appearing in the target are escaped.
.It Fl MT Ar target
Set the name of the
.Xr make 1
target appearing in the generated dependency information.
The default is the name of the input file with its suffix replaced
with the suffix for object files, normally
.Pa .o .
.\" If this option is given more than once, all named targets will
.\" be emitted.
.\" (The current operating mode framework doesn't support that.)
.El
.Ss More Include Path Options
.Bl -tag -width bubblebabble
.It Fl idirafter Ar path
Add the specified path to the
.Dq afterwards
include path.
This path is searched after all directories specified with
.Fl I
and the standard system directories.
Directories on this path are treated as containing system include
files.
.It Fl imacros Ar file
Read in
.Ar file
prior to reading the main input file, and preprocess it, but throw
away the output and retain only the macro definitions.
.It Fl include Ar file
Read in and preprocess
.Ar file
prior to reading the main input file.
.It Fl iprefix Ar prefix
Set the path prefix used with the
.Fl iwithprefix
option.
.It Fl iquote Ar path
Add
.Ar path
to the list of directories searched for include directives written
with quotes.
This list is not searched for include directives written with angle
brackets.
.It Fl iremap Ar string:replacement
Substitute
.Ar replacement
for
.Ar string
in the
.Dv __FILE__
built-in macro.
Not supported.
.It Fl isysroot Ar path
Use
.Ar path
as the
.Dq system root ,
that is, the directory under which the standard system paths are found.
.It Fl isystem Ar path
Add
.Ar path
to the list of system include directories.
This list is searched after the list given with
.Ar I .
Files found on this path are treated as system headers.
.It Fl iwithprefix Ar dir
Splice
.Ar dir
onto the prefix given with
.Fl iprefix
and add this directory as if it were specified with
.Fl idirafter .
.It Fl iwithprefixbefore
Like
-Fl iwithprefix
but adds the result as if it were specified with
.Fl I .
.El
.Ss Diagnostic Options
.Bl -tag -width bubblebabble
.It Fl dD
Dump all macro definitions, except for the predefined macros, after
the normal preprocessing output.
Not implemented.
.It Fl dI
Dump all include directives along with the normal preprocessing
output.
Not implemented.
.It Fl dM
Dump all macro definitions instead of the normal preprocessing
output.
Not implemented.
.It Fl dN
Like
.Fl dD
but emits only macro names and not the expansions.
Not implemented.
.It Fl H
Output a trace of the include tree as it gets processed.
Not implemented.
.El
.Ss Other Options
.Bl -tag -width bubblebabble
.It Fl CC
Retain comments in output.
Same as
.Fl C ,
accepted for compatibility with
.Xr gcc 1 .
.It Fl fdollars-in-identifiers , Fl fno-dollars-in-identifiers
Enable
.Pq or disable, respectively
the use of the dollar sign in identifiers.
Not implemented.
.It Fl ftabstop=num
Set the tab width to the specified value, for reporting column
positions in diagnostics.
The default is 8.
Not implemented.
.It Fl std=standard
Ask
.Nm
to conform to the named standard.
The default, and the only supported value, is
.Dq krc .
.It Fl traditional
This option is accepted for compatibility with
.Xr gcc 1
and ignored.
.It Fl x Ar lang
Adjust the preprocessor for the given language.
The only values accepted for
.Ar lang
are
.Dq assembler-with-cpp
and
.Dq c ,
neither of which have any effect on the behavior of
.Nm .
.El
.Sh FILES
The default list of directories searched for include files is:
.Bl -item -offset indent -compact
.It
.Pa /usr/local/include
.It
.Pa /usr/include
.El
.Sh SEE ALSO
.Xr cc 1 ,
.Xr cpp 1 ,
.Xr make 1
.Sh STANDARDS
None.
The whole point of a traditional cpp is that it reflects practices
in pre-standardization implementations of C.
Some information is available from the first edition of Kernighan and
Ritchie.
Much of the rest of the behavior is based on lore, pragmatism,
material encountered in the wild, and comparison to other
implementations.
.Sh HISTORY
The original version of
.Nm
was written one evening in late 2010.
This version had some problems and was put aside.
The first working version was released in June 2013.
.\" .Sh AUTHORS
.\" .An David A. Holland
.Sh BUGS
Probably plenty.
+246
View File
@@ -0,0 +1,246 @@
/*-
* 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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include "utils.h"
#define MALLOCDEBUG
const char ws[] =
" \t\f\v"
;
const char alnum[] =
"0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_"
;
////////////////////////////////////////////////////////////
// malloc
#define ROUNDUP(len, size) ((size) * (((len) + (size) - 1) / (size)))
#ifdef MALLOCDEBUG
struct mallocheader {
struct mallocheader *self;
size_t len;
};
static
size_t
adjustsize(size_t len)
{
const size_t sz = sizeof(struct mallocheader);
return ROUNDUP(len, sz) + 2*sz;
}
static
void *
placeheaders(void *block, size_t len)
{
struct mallocheader *bothdr, *tophdr;
size_t roundedlen;
void *ret;
roundedlen = ROUNDUP(len, sizeof(struct mallocheader));
bothdr = block;
bothdr->len = len;
bothdr->self = block;
ret = bothdr + 1;
tophdr = (void *)(((unsigned char *)ret) + roundedlen);
tophdr->len = len;
tophdr->self = bothdr;
return ret;
}
static
void *
checkheaders(void *block, size_t len)
{
struct mallocheader *bothdr, *tophdr;
size_t roundedlen;
if (block == NULL) {
assert(len == 0);
return block;
}
roundedlen = ROUNDUP(len, sizeof(struct mallocheader));
bothdr = block;
bothdr--;
assert(bothdr->self == bothdr);
assert(bothdr->len == len);
tophdr = (void *)(((unsigned char *)(bothdr + 1)) + roundedlen);
assert(tophdr->self == bothdr);
assert(tophdr->len == len);
return bothdr;
}
#else
#define adjustsize(len) (len)
#define placeheaders(block, len) ((void)(len), (block))
#define checkheaders(ptr, len) ((void)(len), (ptr))
#endif /* MALLOCDEBUG */
void *
domalloc(size_t len)
{
void *ret;
size_t blocklen;
blocklen = adjustsize(len);
ret = malloc(blocklen);
if (ret == NULL) {
complain(NULL, "Out of memory");
die();
}
return placeheaders(ret, len);
}
void *
dorealloc(void *ptr, size_t oldlen, size_t newlen)
{
void *ret;
void *blockptr;
size_t newblocklen;
blockptr = checkheaders(ptr, oldlen);
newblocklen = adjustsize(newlen);
ret = realloc(blockptr, newblocklen);
if (ret == NULL) {
complain(NULL, "Out of memory");
die();
}
return placeheaders(ret, newlen);
}
void
dofree(void *ptr, size_t len)
{
void *blockptr;
blockptr = checkheaders(ptr, len);
free(blockptr);
}
////////////////////////////////////////////////////////////
// string allocators
char *
dostrdup(const char *s)
{
char *ret;
size_t len;
len = strlen(s);
ret = domalloc(len+1);
strcpy(ret, s);
return ret;
}
char *
dostrdup2(const char *s, const char *t)
{
char *ret;
size_t len;
len = strlen(s) + strlen(t);
ret = domalloc(len+1);
strcpy(ret, s);
strcat(ret, t);
return ret;
}
char *
dostrdup3(const char *s, const char *t, const char *u)
{
char *ret;
size_t len;
len = strlen(s) + strlen(t) + strlen(u);
ret = domalloc(len+1);
strcpy(ret, s);
strcat(ret, t);
strcat(ret, u);
return ret;
}
char *
dostrndup(const char *s, size_t len)
{
char *ret;
ret = domalloc(len+1);
memcpy(ret, s, len);
ret[len] = '\0';
return ret;
}
void
dostrfree(char *s)
{
dofree(s, strlen(s)+1);
}
////////////////////////////////////////////////////////////
// other stuff
size_t
notrailingws(char *buf, size_t len)
{
while (len > 0 && strchr(ws, buf[len-1])) {
buf[--len] = '\0';
}
return len;
}
bool
is_identifier(const char *str)
{
size_t len;
len = strlen(str);
if (len != strspn(str, alnum)) {
return false;
}
if (str[0] >= '0' && str[0] <= '9') {
return false;
}
return true;
}
+72
View File
@@ -0,0 +1,72 @@
/*-
* 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;
#if defined(__CLANG__) || defined(__GNUC__)
#define PF(a, b) __attribute__((__format__(__printf__, a, b)))
#define DEAD __attribute__((__noreturn__))
#define UNUSED __attribute__((__unused__))
#else
#define PF(a, b)
#define DEAD
#define UNUSED
#endif
#define HOWMANY(arr) (sizeof(arr)/sizeof((arr)[0]))
extern const char ws[];
extern const char alnum[];
void *domalloc(size_t len);
void *dorealloc(void *ptr, size_t oldlen, size_t newlen);
void dofree(void *ptr, size_t len);
char *dostrdup(const char *s);
char *dostrdup2(const char *s, const char *t);
char *dostrdup3(const char *s, const char *t, const char *u);
char *dostrndup(const char *s, size_t len);
void dostrfree(char *s);
size_t notrailingws(char *buf, size_t len);
bool is_identifier(const char *str);
/* in place.c */
void complain_init(const char *progname);
void complain(const struct place *, const char *fmt, ...) PF(2, 3);
void complain_fail(void);
bool complain_failed(void);
/* in main.c */
void freestringlater(char *s);
DEAD void die(void);
+33
View File
@@ -0,0 +1,33 @@
/*-
* 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.
*/
#define VERSION_MAJOR "0"
#define VERSION_MINOR "4"
#define VERSION_STRING "0.4"
#define VERSION_LONG "NetBSD tradcpp 0.4"