/*
* Routines to implement a C preprocessor
*/
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "ansi.h"
#include "files.h"
#include "hash.h"
#include "host.h"
#include "buffer.h"
#include "cpp.h"
#include "cpp_hide.h"
#include "cpp_eval.h"
#include "allocate.h"
#include "config.h"
extern int translate_comments;
#undef NULL
#define NULL 0L
#ifndef MAX_SEARCH
#define MAX_SEARCH 32
#endif
static cpp_file_t *open_files;
static scan_position_t *curpos;
unsigned char cpp_char_class[128];
static char class_initialized;
#define add(buf,c) buf_add(buf, (int)(c))
#define UNHANDLED() unhandled(__FILE__, __LINE__)
static buffer_t cppbuf;
static buffer_initialized;
static char *search_paths[MAX_SEARCH];
static int search_index;
/*
* The following vars control the state of conditionals
*/
static cpp_control_state_t control_state;
#define scanning() (control_state.cur_scope == control_state.gen_scope)
#define skipping() (control_state.cur_scope != control_state.gen_scope)
#define parsing() (control_state._parsing)
#define want_comments(x) ((translate_comments) ? x : NULL)
static char *orig_file;
static char *last_file;
static int last_line;
#define FN fname()
#define LN fline()
static int grok_actual_param _ANSI_PROTO_((int));
static int scan_default _ANSI_PROTO_((buffer_t*,int));
static char*
fname()
{
if (curpos == NULL) {
assert(last_file != NULL);
return last_file;
}
if (curpos->scan_pos == 0) return NULL;
return file_name(curpos->scan_pos);
}
static int
fline()
{
if (curpos == NULL) {
assert(last_line != 0);
return last_line;
}
return line_number(curpos->scan_pos);
}
static void
range_check(n, max, msg)
int n, max;
char *msg;
{
if (n >= max) {
fatal(FN, LN, "%s: %d > %d", msg, n+1, max);
}
}
static void
unhandled(file, line)
char *file;
int line;
{
fatal(FN, LN, "Unhandled case %s:%d", file, line);
}
static void
bad_directive()
{
if (scanning()) {
error(FN, LN, "Undefined preprocessor directive");
}
}
static void
bad_include()
{
error(FN,LN,"Malformed include directive");
}
static void
unexpected(msg)
char *msg;
{
error(FN, LN, "Unexpected %s", msg);
}
static void
unexpected_eof(msg)
char *msg;
{
char buf[128];
sprintf(buf, "end of file %s", msg);
unexpected(buf);
}
static void
unexpected_eol(msg)
char *msg;
{
char buf[128];
sprintf(buf, "end of line %s", msg);
unexpected(buf);
}
static char*
charstr(c)
int c;
{
if (is_eof(c)) return "end of file";
if (is_eol(c)) return "end of line";
if (is_alpha(c)) return "identifier";
if (is_digit(c)) return "number";
if (is_white(c)) return "white space";
if (is_punct(c)) return "puctuation";
return "crap";
}
static void
expected(msg, c)
char *msg;
int c;
{
error(FN, LN, "Expected %s got %s", msg, charstr(c));
}
static int
levels_nested()
{
scan_position_t *p;
int level = 0;
for (p = curpos; p; p = p->scan_next) {
if (p->scan_kind == scan_file) {
level++;
}
}
return level;
}
static void
add_position_directive(buf, new_line)
buffer_t *buf;
int new_line;
{
char b[40];
sprintf(b, "\n# %d \"", LN);
buf_add_str(buf, b);
buf_add_str(buf, FN);
sprintf(b, "\" %d", levels_nested());
buf_add_str(buf, b);
if (new_line) {
add(buf, '\n');
}
}
static void
init_char_class()
{
int i;
if (class_initialized) return;
cpp_char_class[0] = END_INPUT;
cpp_char_class[PARAM_START] = PARAM_START;
cpp_char_class['#'] = MSTART;
cpp_char_class['_'] = ALPHA;
cpp_char_class['$'] = ALPHA;
for (i = 'g'; i <= 'z'; i++) {
cpp_char_class[i] = ALPHA;
}
for (i = 'G'; i <= 'Z'; i++) {
cpp_char_class[i] = ALPHA;
}
for (i = 'A'; i <= 'F'; i++) {
cpp_char_class[i] = ALPHA | XDIGIT;
}
for (i = 'a'; i <= 'f'; i++) {
cpp_char_class[i] = ALPHA | XDIGIT;
}
for (i = '0'; i <= '7'; i++) {
cpp_char_class[i] = DIGIT | XDIGIT;
}
cpp_char_class['8'] = DIGIT | XDIGIT;
cpp_char_class['9'] = DIGIT | XDIGIT;
cpp_char_class[' '] = WHITE;
cpp_char_class[''] = WHITE;
cpp_char_class['\t'] = WHITE;
cpp_char_class['\n'] = END_OF_LINE;
class_initialized = 1;
}
static void
init_cppbuf()
{
if (buffer_initialized) {
return;
}
buf_init(&cppbuf);
}
static void
rm_file_from_list(f)
cpp_file_t *f;
{
cpp_file_t *p, *last;
for (p = open_files, last = NULL; p; p = p->next_cpp_file) {
if (p == f) break;
last = p;
}
assert(p == f);
if (last == NULL) {
open_files = f->next_cpp_file;
}
else {
last->next_cpp_file = f->next_cpp_file;
}
}
static cpp_file_t*
find_open_file(path)
char *path;
{
cpp_file_t *f;
for (f = open_files; f; f = f->next_cpp_file) {
assert(f->next_cpp_file != f);
if (! strcmp(f->path, path)) {
return f;
}
}
return NULL;
}
void
cpp_search_path(path)
char *path;
{
buffer_t buf;
if (search_index >= MAX_SEARCH) {
fatal(__FILE__,__LINE__,"Too many search paths added");
}
buf_init(&buf);
buf_add_str(&buf, path);
for (; *path && path[1]; path++);
if (*path != '/') {
add(&buf, '/');
}
search_paths[search_index++] = buf_get_str(&buf);
}
static cpp_file_t*
attempt_open(path)
char *path;
{
cpp_file_t *f;
char *mapaddr;
size_t fsize;
int fd;
f = find_open_file(path);
if (f != NULL) {
f->reference_count++;
return f;
}
if ((fd = open(path, O_RDONLY)) == -1) {
/* Can't access for reading */
return NULL;
}
if ((fsize = sizeof_file(fd)) == -1) {
close(fd);
return NULL;
}
mapaddr = (char*) map_file(fd, fsize);
if (mapaddr == (char*)-1) {
/* failed mmap */
close(fd);
return NULL;
}
f = (cpp_file_t*) allocate(sizeof(cpp_file_t));
f->path = new_string(path);
f->fd = fd;
f->text = mapaddr;
f->file_size = fsize;
f->reference_count = 1;
assert(open_files != f);
f->next_cpp_file = open_files;
open_files = f;
return f;
}
static void
push_file(buf, f)
buffer_t *buf;
cpp_file_t *f;
{
scan_position_t *pos;
pos = (scan_position_t*) allocate(sizeof(scan_position_t));
pos->scan_kind = scan_file;
pos->scan.file = f;
pos->scan_index = 0;
pos->scan_pos = add_file(f->path);
pos->scan_next = curpos;
curpos = pos;
add_position_directive(buf,1);
}
int
cpp_open(path)
char *path;
{
cpp_file_t *f;
init_char_class();
init_cppbuf();
control_state.skip_else = 0;
control_state.cur_scope = 0;
control_state.gen_scope = 0;
control_state._parsing = 0;
f = attempt_open(path);
if (f == NULL) {
return 1;
}
orig_file = new_string(path);
push_file(&cppbuf,f);
return 0;
}
void
cpp_cleanup()
{
cpp_file_t *f, *next;
curpos = NULL;
for (f = open_files; f; f = next) {
next = f->next_cpp_file;
unmap_file(f->text, f->file_size);
close(f->fd);
deallocate(f);
}
open_files = NULL;
buf_destroy(&cppbuf);
}
void
cpp_set_state(newpos, new_state, savepos, save_state)
scan_position_t *newpos, **savepos;
cpp_control_state_t *new_state, *save_state;
{
*savepos = curpos;
*save_state = control_state;
control_state = *new_state;
curpos = newpos;
}
static void
kill_file(f)
cpp_file_t *f;
{
unmap_file(f->text, f->file_size);
close(f->fd);
rm_file_from_list(f);
deallocate(f);
}
static void
finished_with(s)
scan_position_t *s;
{
cpp_file_t *f;
last_file = file_name(s->scan_pos);
last_line = line_number(s->scan_pos);
switch (s->scan_kind) {
case scan_file:
f = curpos->scan.file;
deallocate(s);
f->reference_count--;
if (f->reference_count == 0) {
kill_file(f);
}
break;
case scan_macro_expansion:
case scan_text:
deallocate(s);
break;
default:
assert(0);
break;
}
}
static void
unget_char()
{
if (curpos == NULL) return;
assert(curpos->scan_index > 0);
curpos->scan_index--;
}
static int
next_char()
{
register scan_position_t *cp = curpos; /* Get global curpos into a reg */
cpp_file_t *f;
macro_t *m;
scan_position_t *next;
scan_kind_t kind;
int result;
top:
if (cp == NULL) {
return 0;
}
kind = cp->scan_kind;
if (kind == scan_file) {
f = cp->scan.file;
if (cp->scan_index >= f->file_size) {
next = cp->scan_next;
finished_with(cp);
cp = curpos = next;
goto top;
}
result = f->text[cp->scan_index++];
}
else if (kind == scan_macro_expansion) {
m = cp->scan.expansion.expand_macro;
if (cp->scan_index >= m->macro_body_len) {
next = cp->scan_next;
finished_with(cp);
cp = curpos = next;
goto top;
}
result = m->macro_body[cp->scan_index++];
}
else {
assert(kind == scan_text);
result = cp->scan.text[cp->scan_index++];
if (result == 0) {
next = cp->scan_next;
finished_with(cp);
cp = curpos = next;
goto top;
}
}
return result;
}
static void
incline(sync)
int sync;
{
if (sync) {
control_state.position++;
}
else {
/* force file position directive to be added */
control_state.position = 0;
}
switch (curpos->scan_kind) {
case scan_file:
curpos->scan_pos++;
break;
default:
break;
}
}
static void
check_position(buf)
buffer_t *buf;
{
if (parsing()) return;
switch (curpos->scan_kind) {
case scan_file:
if (control_state.position != curpos->scan_pos) {
control_state.position = curpos->scan_pos;
add_position_directive(buf, 0);
}
break;
default:
assert(0);
break;
}
}
static void
comment_start(buf)
buffer_t *buf;
{
if (translate_comments && buf != NULL) {
add(buf, '/');
add(buf, '*');
}
}
static void
cpp_comment_start(buf)
buffer_t *buf;
{
if (translate_comments && buf != NULL) {
add(buf, '/');
add(buf, '/');
}
}
static int
scan_white(buf, c)
buffer_t *buf;
int c;
{
while (is_white(c)) {
if (buf != NULL) {
add(buf, c);
}
c = next_char();
}
return c;
}
static int
skip_white(c)
int c;
{
return scan_white(NULL, c);
}
static int
skip_c_comment(buf, c)
buffer_t *buf;
int c;
{
c = next_char();
for (;;) {
switch (classof(c)) {
case END_INPUT:
return c;
case END_OF_LINE:
incline(0);
add(buf,c);
c = next_char();
break;
case PUNCT:
switch (c) {
case '*':
add(buf,'*');
c = next_char();
if (c == '/') {
add(buf,'/');
return next_char();
}
break;
case '\\':
add(buf,c);
c = next_char();
add(buf,c);
if (is_eol(c)) {
incline(0);
}
else if (is_eof(c)) {
return c;
}
c = next_char();
break;
default:
add(buf,c);
c = next_char();
break;
}
break;
default:
c = scan_default(buf, c);
break;
}
}
}
static int
skip_cpp_comment(buf, c)
buffer_t *buf;
int c;
{
buffer_t lbuf;
c = next_char();
for (;;) {
switch (classof(c)) {
case END_INPUT:
return c;
case DIGIT | XDIGIT:
case ALPHA:
case ALPHA | XDIGIT:
case WHITE:
case MSTART:
case PARAM_START:
case PUNCT:
add(buf,c);
c = next_char();
break;
case END_OF_LINE:
add(buf,c);
/* incline(0); */
/* c = next_char(); */
return c;
default:
UNHANDLED();
break;
}
}
}
static int
scan_to_end(buf, c)
buffer_t *buf;
int c;
{
while (! (is_eol(c) || is_eof(c))) {
switch (c) {
case '/':
c = next_char();
if (c == '*') {
comment_start(buf);
c = skip_c_comment(want_comments(buf), c);
}
else if (c == '/') {
cpp_comment_start(buf);
c = skip_cpp_comment(want_comments(buf), c);
}
else {
add(buf,'/');
}
break;
case '\\':
c = next_char();
if (is_eol(c)) {
incline(0);
c = next_char();
}
else if (is_eof(c)) {
if (buf != NULL) {
add(buf, '\\');
}
return c;
}
else if (c == '\\') {
if (buf != NULL) {
add(buf, '\\');
add(buf, '\\');
}
c = next_char();
}
else if (buf != NULL) {
add(buf, '\\');
}
break;
default:
if (buf != NULL) {
add(buf, c);
}
c = next_char();
break;
}
}
return c;
}
static int
skip_to_end(c)
int c;
{
return scan_to_end(NULL, c);
}
static int
finish_num(buf, c, mask)
buffer_t *buf;
int c, mask;
{
while (! is_eof(c)) {
if ((cpp_char_class[c] & mask) == 0) break;
add(buf, c);
c = next_char();
}
return c;
}
static int
maybe_magnitude(buf, c)
buffer_t *buf;
int c;
{
if (c == 'e' || c == 'E') {
add(buf, c);
c = next_char();
if (c == '+' || c == '-') {
add(buf, c);
c = next_char();
}
c = finish_num(buf, c, DIGIT);
}
return c;
}
static int
scan_number(buf, c)
buffer_t *buf;
int c;
{
add(buf, c);
if (c == '0') {
c = next_char();
if (c == 'x' || c == 'X') {
add(buf, c);
c = finish_num(buf, next_char(), XDIGIT);
}
else {
c = finish_num(buf, c, DIGIT);
}
}
else {
c = finish_num(buf, next_char(), DIGIT);
}
if (int_modifier(c)) {
do {
add(buf, c);
c = next_char();
} while (int_modifier(c));
return c;
}
if (c == '.') {
add(buf, c);
c = finish_num(buf, next_char(), DIGIT);
c = maybe_magnitude(buf, c);
if (float_modifier(c)) {
add(buf, c);
c = next_char();
}
return c;
}
c = maybe_magnitude(buf, c);
if (int_modifier(c)) {
do {
add(buf, c);
c = next_char();
} while (int_modifier(c));
}
return c;
}
static int
scan_ident(buf, c)
buffer_t *buf;
int c;
{
for (;;) {
add(buf, c);
c = next_char();
if (!is_alpha_numeric(c)) break;
}
return c;
}
static int
scan_to_del(buf, c, del)
buffer_t *buf;
int c, del;
{
for (;;) {
switch (classof(c)) {
case END_INPUT:
case END_OF_LINE:
return c;
case PUNCT:
switch (c) {
case '\\':
c = next_char();
if (is_eol(c)) {
incline(0);
c = next_char();
}
else if (c == '\'' || c == '"' || c == '\\') {
add(buf, '\\');
add(buf, c);
c = next_char();
}
else {
add(buf, '\\');
}
break;
default:
if (c == del) {
return c;
}
add(buf, c);
c = next_char();
break;
}
break;
default:
c = scan_default(buf,c);
break;
}
}
}
static int
scan_string(buf, c)
buffer_t *buf;
int c;
{
c = scan_to_del(buf, c, '"');
if (c != '"') {
expected("'\"'", c);
}
else {
add(buf, c);
return next_char();
}
}
static int
scan_char_const(buf, c)
buffer_t *buf;
int c;
{
c = scan_to_del(buf, c, '\'');
if (c != '\'') {
expected("single quote", c);
}
else {
add(buf, c);
return next_char();
}
}
static int
grok_formals(formals, nformals, buf, c)
char ***formals;
int *nformals;
buffer_t *buf;
int c;
{
char *f[256];
char **fp;
int nf = 0;
int i;
for (;;) {
c = skip_white(c);
if (! is_alpha(c)) break;
c = scan_ident(buf, c);
range_check(nf, 256, "Too many formal parameters");
f[nf++] = buf_get_str(buf);
c = skip_white(c);
if (c != ',') break;
c = next_char();
}
*nformals = nf;
if (nf == 0) {
*formals = NULL;
}
else {
fp = (char**) malloc(sizeof(char*) * nf);
for (i = 0; i < nf; i++) {
fp[i] = f[i];
}
*formals = fp;
}
return c;
}
static char*
local_copy(buf, str, size)
buffer_t *buf;
char *str;
int size;
{
int len = buf_count(buf);
if (len < size) {
buf_move_to(buf, str);
return str;
}
return buf_get_str(buf);
}
static void
grok_param(outbuf, idbuf, formals, nformals, xpect)
buffer_t *outbuf, *idbuf;
char *formals[];
int nformals, xpect;
{
char ident[128];
char *name;
int i;
name = local_copy(idbuf, ident, sizeof(ident));
for (i = 0; i < nformals; i++) {
if (! strcmp(name, formals[i])) {
add(outbuf, PARAM_START);
add(outbuf, i+1);
goto end_subp;
}
}
if (xpect) {
error(FN, LN, "Expected macro formal got %s", name);
}
buf_add_str(outbuf, name);
end_subp:
if (name != ident) {
free(name);
}
}
static int
scan_default(buf, c)
buffer_t *buf;
int c;
{
switch (classof(c)) {
case END_INPUT:
return c;
case END_OF_LINE:
incline(buf != NULL);
add(buf, c);
c = next_char();
break;
case MSTART:
add(buf, c);
c = next_char();
break;
case WHITE:
add(buf, c);
return next_char();
case ALPHA:
case ALPHA | XDIGIT:
c = scan_ident(buf, c);
break;
case DIGIT | XDIGIT:
return scan_number(buf, c);
case PARAM_START:
if (buf) {
c = grok_actual_param(next_char());
} else {
c = next_char();
c = next_char();
}
break;
case PUNCT:
switch (c) {
case '"':
add(buf, c);
c = scan_string(buf, next_char());
break;
case '\'':
add(buf, c);
c = scan_char_const(buf, next_char());
break;
case '/':
c = next_char();
if (c == '*') {
comment_start(buf);
c = skip_c_comment(want_comments(buf), c);
}
else if (c == '/') {
cpp_comment_start(buf);
c = skip_cpp_comment(want_comments(buf), c);
}
else {
add(buf,'/');
}
break;
case '\\':
c = next_char();
switch (c) {
case '\n':
incline(0);
c = next_char();
break;
case '\\':
add(buf, '\\');
add(buf, '\\');
c = next_char();
break;
default:
add(buf, '\\');
break;
}
break;
default:
add(buf, c);
c = next_char();
break;
}
break;
default:
UNHANDLED();
break;
}
return c;
}
static int
grok_define(buf, c)
buffer_t *buf;
int c;
{
buffer_t lbuf;
char *macro_name;
char *macro_body;
char **formals;
file_pos_t defpos;
int nformals;
int body_len;
c = skip_white(c);
if (!is_alpha(c)) {
expected("idetifier", c);
return skip_to_end(c);
}
defpos = curpos->scan_pos;
buf_init(buf);
c = scan_ident(buf, c);
macro_name = buf_get_str(buf);
if (c == '(') {
c = grok_formals(&formals, &nformals, buf, next_char());
if (c == ')') {
c = next_char();
}
else {
expected("')'", c);
}
}
else {
nformals = -1;
}
c = skip_white(c);
if (nformals == -1) {
buf_init(buf);
c = scan_to_end(buf, c);
body_len = buf_count(buf);
macro_body = buf_get_str(buf);
}
else {
buf_init(buf);
while (!is_eol(c) && !is_eof(c)) {
switch (classof(c)) {
case MSTART:
c = next_char();
if (c == '#') {
c = next_char();
break;
}
c = skip_white(c);
if (! is_alpha(c)) {
expected("macro formal parameter name", c);
}
else {
add(buf, '"');
buf_init(&lbuf);
c = scan_ident(&lbuf, c);
grok_param(buf, &lbuf, formals, nformals, 1);
add(buf, '"');
}
break;
case ALPHA:
case ALPHA | XDIGIT:
buf_init(&lbuf);
c = scan_ident(&lbuf, c);
grok_param(buf, &lbuf, formals, nformals, 0);
break;
default:
c = scan_default(buf, c);
break;
}
}
body_len = buf_count(buf);
macro_body = buf_get_str(buf);
}
macro_def(macro_name, macro_body, body_len, nformals, defpos);
return c;
}
static int
grok_if(buf, c)
buffer_t *buf;
int c;
{
char ident[256];
char *name;
cpp_eval_result_t result;
assert(control_state.cur_scope >= 0);
assert(control_state.gen_scope >= 0);
buf_init(buf);
c = scan_to_end(buf, c);
name = local_copy(buf, ident, sizeof(ident));
result = cpp_eval(name);
++control_state.cur_scope;
control_state.skip_else = 0;
if (EVAL_FAILED(result) || !IS_EVAL_INT(result)) {
;
}
else {
if (EVAL_INT(result) != 0) {
++control_state.gen_scope;
}
}
end_subp:
if (name != ident) {
free(name);
}
return c;
}
static int
grok_elif(buf, c)
buffer_t *buf;
int c;
{
char ident[256];
char *name;
cpp_eval_result_t result;
assert(control_state.cur_scope >= 0);
assert(control_state.gen_scope >= 0);
if (control_state.cur_scope == 0) {
error(FN,LN,"elif directive found without a matching if directive");
return skip_to_end(c);
}
if (control_state.skip_else) {
return skip_to_end(c);
}
if (scanning()) {
control_state.skip_else = 1;
control_state.gen_scope--;
return skip_to_end(c);
}
if (control_state.gen_scope != control_state.cur_scope - 1) {
return skip_to_end(c);
}
buf_init(buf);
c = scan_to_end(buf, c);
name = local_copy(buf, ident, sizeof(ident));
result = cpp_eval(name);
/*
++control_state.cur_scope;
*/
/*
control_state.skip_else = 0;
*/
if (EVAL_FAILED(result) || !IS_EVAL_INT(result)) {
;
}
else {
if (EVAL_INT(result) != 0) {
++control_state.gen_scope;
}
}
end_subp:
if (name != ident) {
free(name);
}
return c;
}
static int
grok_ifdef(buf, c, sense)
buffer_t *buf;
int c;
int sense;
{
char ident[128];
char *name;
macro_t *m;
control_state.skip_else = 0;
c = skip_white(c);
if (! is_alpha(c)) {
expected("identifier", c);
return skip_to_end(c);
}
c = scan_ident(buf, c);
name = local_copy(buf, ident, sizeof(ident));
++control_state.cur_scope;
m = macro_find(name);
if ((m != NULL && !sense) || (m == NULL && sense)) {
++control_state.gen_scope;
}
if (name != ident) {
free(name);
}
return skip_to_end(c);
}
static int
grok_else(buf, c)
buffer_t *buf;
int c;
{
int was_skipping = skipping();
assert(control_state.cur_scope >= 0);
assert(control_state.gen_scope >= 0);
if (control_state.cur_scope == 0) {
error(FN, LN, "Unmatched else directive");
return skip_to_end(c);
}
else {
if (! control_state.skip_else) {
control_state.skip_else = 0;
if (control_state.gen_scope == control_state.cur_scope) {
--control_state.gen_scope;
}
else if (control_state.gen_scope == control_state.cur_scope -1 ) {
++control_state.gen_scope;
}
}
}
if (scanning() && was_skipping) {
add_position_directive(buf, 0);
}
return skip_to_end(c);
}
static int
grok_endif(buf, c)
buffer_t *buf;
int c;
{
int was_skipping = skipping();
assert(control_state.cur_scope >= 0);
assert(control_state.gen_scope >= 0);
if (control_state.cur_scope == 0) {
error(FN, LN, "Unmatched endif directive");
return skip_to_end(c);
}
else {
control_state.skip_else = 0;
if (control_state.gen_scope == control_state.cur_scope) {
--control_state.gen_scope;
}
--control_state.cur_scope;
}
if (scanning() && was_skipping) {
add_position_directive(buf, 0);
}
return skip_to_end(c);
}
static void
grok_pathof(buf, path)
buffer_t *buf;
char *path;
{
char *last = NULL;
char *p;
for (p = path; *p; p++) {
if (*p == '/') {
last = p+1;
}
}
if (last != NULL) {
for (p = path; p != last; p++) {
add(buf, *p);
}
}
}
static int
search_for_file(buf, lbuf, name, stdinc)
buffer_t *buf, *lbuf;
char *name;
int stdinc;
{
char *path;
cpp_file_t *f;
int i;
char ident[128];
if (name[0] == '/') {
f = attempt_open(name);
if (f != NULL) {
push_file(buf, f);
goto end_of_subp;
}
goto failed;
}
if (!stdinc) {
f = attempt_open(name);
if (f != NULL) {
push_file(buf, f);
goto end_of_subp;
}
/*
** #include "file" semantics are to search for "file"
** in the directory of the original source file.
*/
buf_init(lbuf);
grok_pathof(lbuf, orig_file);
if (buf_count(lbuf)) {
buf_add_str(lbuf, name);
path = local_copy(lbuf, ident, sizeof(ident));
f = attempt_open(path);
if (path != ident) {
free(path);
}
if (f != NULL) {
push_file(buf, f);
goto end_of_subp;
}
}
}
for (i = 0; i < search_index; i++) {
buf_init(lbuf);
buf_add_str(lbuf, search_paths[i]);
buf_add_str(lbuf, name);
path = local_copy(lbuf, ident, sizeof(ident));
f = attempt_open(path);
if (path != ident) {
free(path);
}
if (f != NULL) {
push_file(buf,f);
goto end_of_subp;
}
}
buf_init(lbuf);
buf_add_str(lbuf, "/usr/include/");
buf_add_str(lbuf, name);
path = local_copy(lbuf, ident, sizeof(ident));
f = attempt_open(path);
if (path != ident) {
free(path);
}
if (f != NULL) {
push_file(buf,f);
goto end_of_subp;
}
failed:
error(FN,LN,"Couldn't open %s", name);
end_of_subp:
return next_char();
}
static int
grok_include(buf, lbuf, c)
buffer_t *buf, *lbuf;
int c;
{
char ident[64];
char *name;
int del;
del = skip_white(c);
switch (del) {
case '<':
del = '>';
/* fall through */
case '"':
buf_init(lbuf);
c = scan_to_del(lbuf, next_char(), del);
if (c != del) {
goto bad_input;
}
c = skip_to_end(c);
unget_char();
break;
default:
bad_input:
bad_include();
return skip_to_end(c);
}
name = local_copy(lbuf, ident, sizeof(ident));
c = search_for_file(buf, lbuf, name, del == '>');
if (name != ident) {
free(name);
}
return c;
}
static int
grok_error(buf, c)
buffer_t *buf;
int c;
{
char ident[128];
char *msg;
buf_init(buf);
c = skip_white(c);
c = scan_to_end(buf, c);
msg = local_copy(buf, ident, sizeof(ident));
error(FN,LN,msg);
if (msg != ident) {
free(msg);
}
return c;
}
static int
grok_undef(buf, c)
buffer_t *buf;
int c;
{
char ident[128];
char *name;
c = skip_white(c);
if (! is_alpha(c)) {
expected("macro identifier", c);
return skip_to_end(c);
}
buf_init(buf);
c = scan_ident(buf, c);
name = local_copy(buf, ident, sizeof(ident));
macro_undef(name);
if (name != ident) {
free(name);
}
return skip_to_end(c);
}
static int
scan_directive(buf, c)
buffer_t *buf;
int c;
{
#ifdef PUBLIC
struct resword {char *name; int token;};
extern struct resword *cpp_rsvd();
struct resword *r;
#endif
buffer_t lbuf;
char ident[32];
int len;
int keywd;
c = skip_white(c);
if (is_eof(c) || is_eol(c)) {
return c;
}
if (!is_alpha(c)) {
bad_directive();
return skip_to_end(c);
}
buf_init(&lbuf);
c = scan_ident(&lbuf, c);
len = buf_count(&lbuf);
if (len > sizeof(ident)) {
buf_destroy(&lbuf);
bad_directive();
return skip_to_end(c);
}
buf_move_to(&lbuf, ident);
buf_destroy(&lbuf);
#ifdef PUBLIC
if ((r = cpp_rsvd(ident, len)) == NULL) {
#else
if ((keywd = cpp_rsvd(ident)) == -1) {
#endif
bad_directive();
return skip_to_end(c);
}
#ifdef PUBLIC
keywd = r->token;
#endif
if (scanning()) {
switch (keywd) {
case Define: return grok_define(&lbuf, c);
case Elif: return grok_elif(&lbuf, c);
case Else: return grok_else(buf, c);
case Endif: return grok_endif(buf, c);
case Error: return grok_error(&lbuf, c);
case If: return grok_if(&lbuf, c);
case Ifdef: return grok_ifdef(&lbuf, c, 0);
case Ifndef: return grok_ifdef(&lbuf, c, 1);
case Include: return grok_include(buf, &lbuf, c);
case Line:
case Pragma:
case Ident: return skip_to_end(c);
case Undef: return grok_undef(&lbuf, c);
}
}
else {
switch (keywd) {
case Define:
case Include:
case Pragma:
case Undef:
case Error:
case Ident:
case Line:
return skip_to_end(c);
case Elif:
return grok_elif(&lbuf,c);
case Else:
return grok_else(buf, c);
case Endif:
return grok_endif(buf, c);
case If:
case Ifdef:
case Ifndef:
++control_state.cur_scope;
return skip_to_end(c);
}
}
return c;
}
static int
scan_actual(buf,c, level)
buffer_t *buf;
int c;
int level;
{
for (;;) {
switch (classof(c)) {
case END_INPUT:
unexpected_eof("in macro call");
return c;
case PUNCT:
switch (c) {
case '(':
add(buf,c);
c = scan_actual(buf,next_char(),level+1);
if (c != ')') {
expected("')'", c);
}
else {
add(buf, c);
c = next_char();
}
break;
case ')':
return c;
case ',':
if (level == 0) {
return c;
}
add(buf, c);
c = next_char();
break;
case '"':
add(buf, c);
c = scan_string(buf, next_char());
break;
case '\'':
add(buf, c);
c = scan_char_const(buf, next_char());
break;
case '/':
case '\\':
c = next_char();
if (is_eof(c)) {
add(buf,'\\');
return c;
}
switch (c) {
case '\n':
incline(0);
c = next_char();
break;
default:
add(buf,'\\');
add(buf,c);
c = next_char();
break;
}
break;
default:
add(buf, c);
c = next_char();
break;
}
break;
default:
c = scan_default(buf,c);
break;
}
}
}
static int
grok_actuals(actuals, nactuals, buf, c)
char ***actuals;
int *nactuals;
buffer_t *buf;
int c;
{
char *a[256];
char **ap;
int na = 0;
int i;
for (;;) {
c = skip_white(c);
if (is_eof(c)) {
unexpected_eof("in macro call");
return c;
}
if (c == ')') break;
buf_init(buf);
c = scan_actual(buf,c,0);
range_check(na, 256, "Too many actual parameters");
a[na++] = buf_get_str(buf);
c = skip_white(c);
if (c != ',') break;
c = next_char();
}
*nactuals = na;
if (na == 0) {
*actuals = NULL;
}
else {
ap = (char**) malloc(sizeof(char*) * na);
for (i = 0; i < na; i++) {
ap[i] = a[i];
}
*actuals = ap;
}
return c;
}
static int
push_expansion(mac, actuals, nactuals)
macro_t *mac;
char **actuals;
int nactuals;
{
scan_position_t *npos;
npos = (scan_position_t*) allocate(sizeof(scan_position_t));
npos->scan_kind = scan_macro_expansion;
npos->scan.expansion.expand_macro = mac;
npos->scan.expansion.expand_actuals = actuals;
npos->scan.expansion.expand_nactuals = nactuals;
if (curpos != NULL) {
npos->scan_pos = curpos->scan_pos;
}
npos->scan_index = 0;
npos->scan_next = curpos;
curpos = npos;
return next_char();
}
static int
push_string(str)
char *str;
{
scan_position_t *npos;
npos = (scan_position_t*) allocate(sizeof(scan_position_t));
npos->scan_kind = scan_text;
npos->scan.text = str;
npos->scan_pos = curpos->scan_pos;
npos->scan_index = 0;
npos->scan_next = curpos;
curpos = npos;
return next_char();
}
static void
grok_builtin_macro(buf, mac)
buffer_t *buf;
macro_t *mac;
{
char buffer[32];
switch (mac->macro_params) {
case BUILTIN_FILE:
add(buf, '"');
buf_add_str(buf, FN);
add(buf, '"');
break;
case BUILTIN_LINE:
sprintf(buffer, "%d", LN);
buf_add_str(buf, buffer);
break;
default:
assert(0);
break;
}
}
static int
grok_macro_instance(buf, lbuf, c, mac)
buffer_t *buf, *lbuf;
int c;
macro_t *mac;
{
char **actuals;
int nactuals;
if (mac->macro_params < -1) {
grok_builtin_macro(buf, mac);
return c;
}
if (mac->macro_params != -1) {
buf_init(lbuf);
c = scan_white(lbuf, c);
if (c != '(') {
buf_add_str(buf, mac->macro_name);
buf_concat(buf, lbuf);
return c;
}
buf_init(lbuf);
c = grok_actuals(&actuals, &nactuals, lbuf, next_char());
if (c != ')') {
expected("')'", c);
}
}
else {
unget_char();
}
return push_expansion(mac, actuals, nactuals);
}
static int
parenthesized_ident(buf, c)
buffer_t *buf;
int c;
{
for (;;) {
c = skip_white(c);
if (c == '(') {
c = parenthesized_ident(buf, next_char());
if (c != ')') {
return 0;
}
c = next_char();
}
else if (is_alpha(c)) {
do {
add(buf, c);
c = next_char();
} while (is_alpha_numeric(c));
}
else {
return c;
}
}
}
static int
grok_defined(buf, lbuf, c)
buffer_t *buf, *lbuf;
int c;
{
char ident[128];
char *name;
c = skip_white(c);
buf_init(lbuf);
if (c == '(') {
c = parenthesized_ident(lbuf, next_char());
if (c != ')') {
add(buf, BAD_INPUT);
return c;
}
c = next_char();
}
else {
c = scan_ident(lbuf, c);
}
name = local_copy(lbuf, ident, sizeof(ident));
add(buf, ' ');
if (macro_find(name)) {
add(buf, '1');
}
else {
add(buf, '0');
}
add(buf, ' ');
if (name != ident) {
free(name);
}
return c;
}
static int
grok_ident(buf, c)
buffer_t *buf;
int c;
{
buffer_t lbuf;
char ident[128];
char *name;
macro_t *mac;
buf_init(&lbuf);
c = scan_ident(&lbuf, c);
name = local_copy(&lbuf, ident, sizeof(ident));
if (parsing() && !strcmp(name,"defined")) {
return grok_defined(buf, &lbuf, c);
}
if (mac = macro_find(name)) {
c = grok_macro_instance(buf, &lbuf, c, mac);
}
else {
buf_add_str(buf, name);
}
if (name != ident) {
free(name);
}
return c;
}
static int
grok_actual_param(param_ord)
int param_ord;
{
char **actuals;
char *param;
int nactuals;
if (curpos->scan_kind != scan_macro_expansion) {
fatal(FN,LN,"bad param %s:%d %s:%d",__FILE__,__LINE__,
last_file, last_line);
}
assert(curpos->scan_kind == scan_macro_expansion);
actuals = curpos->scan.expansion.expand_actuals;
nactuals = curpos->scan.expansion.expand_nactuals;
if (actuals == NULL || param_ord > nactuals) {
return next_char();
}
param = actuals[param_ord - 1];
if (param == NULL) {
return next_char();
}
return push_string(param);
}
static int
skip(buf, c)
buffer_t *buf;
int c;
{
buffer_t lbuf;
assert(!parsing());
for (;;) {
if (scanning()) {
return c;
}
switch (classof(c)) {
case END_INPUT:
return c;
case MSTART:
c = scan_directive(buf, next_char());
break;
case PUNCT:
switch (c) {
case '"':
buf_init(&lbuf);
c = scan_string(&lbuf, next_char());
buf_destroy(&lbuf);
break;
case '\'':
buf_init(&lbuf);
c = scan_char_const(&lbuf, next_char());
buf_destroy(&lbuf);
break;
case '/':
c = next_char();
if (c == '*') {
c = skip_c_comment(NULL,c);
}
else if (c == '/') {
c = skip_cpp_comment(NULL,c);
}
break;
case '\\':
UNHANDLED();
break;
default:
c = next_char();
break;
}
break;
default:
c = scan_default(NULL, c);
break;
}
}
}
static int
scan(buf)
buffer_t *buf;
{
int c;
c = next_char();
for (;;) {
if (skipping()) {
c = skip(buf, c);
}
assert(scanning());
switch (classof(c)) {
case END_INPUT:
return -1;
case WHITE:
add(buf, c);
return 0;
case END_OF_LINE:
incline(1);
check_position(buf);
add(buf, c);
return 0;
case ALPHA:
case ALPHA | XDIGIT:
c = grok_ident(buf, c);
break;
case MSTART:
if (parsing()) {
add(buf, BAD_INPUT);
return 0;
}
c = scan_directive(buf, next_char());
break;
default:
c = scan_default(buf,c);
break;
}
}
}
#define GET_FROM_BUF(buf)\
while (buf_empty(buf)) {\
if (scan(buf) == -1) break;\
}\
return buf_get(buf);
int
cpp_getc_from(buf)
buffer_t *buf;
{
GET_FROM_BUF(buf);
}
int
cpp_getc()
{
buffer_t *buf = &cppbuf;
GET_FROM_BUF(buf);
}
syntax highlighted by Code2HTML, v. 0.9.1