Implemented #ifdef and #ifndef

This commit is contained in:
Pierre Pronchery 2008-04-24 16:55:58 +00:00
parent 8df40f9cf1
commit eaf6445c46
2 changed files with 222 additions and 36 deletions

View File

@ -98,10 +98,10 @@ typedef enum _CppCode
CPP_CODE_WORD, /* FIXME numbers and keywords? */
CPP_CODE_UNKNOWN
} CppCode;
# define CPP_CODE_LAST CPP_CODE_UNKNOWN
# define CPP_CODE_COUNT (CPP_CODE_LAST + 1)
# define CPP_CODE_META_FIRST CPP_CODE_META_DEFINE
# define CPP_CODE_META_LAST CPP_CODE_META_WARNING
# define CPP_CODE_LAST CPP_CODE_UNKNOWN
# define CPP_CODE_COUNT (CPP_CODE_LAST + 1)
# define CPP_CODE_META_FIRST CPP_CODE_META_DEFINE
# define CPP_CODE_META_LAST CPP_CODE_META_WARNING
/* functions */
@ -111,6 +111,8 @@ void cpp_delete(Cpp * cpp);
/* accessors */
char const * cpp_get_filename(Cpp * cpp);
int cpp_is_defined(Cpp * cpp, char const * name);
/* useful */
int cpp_define_add(Cpp * cpp, char const * name, char const * value);
int cpp_define_remove(Cpp * cpp, char const * name);

248
src/cpp.c
View File

@ -16,12 +16,12 @@
/* FIXME
* - comments are not handled in directives
* - fix includes (system vs regular, inclusion order)
* - implement define and undef
* - implement ifdef and ifndef
* - potential memory leak with tokens' data
* - add a way to tokenize input from a string (and handle "#" and "##") */
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
@ -49,6 +49,13 @@ typedef struct _CppOperator
char const * string;
} CppOperator;
typedef enum _CppScope
{
CPP_SCOPE_NOTYET = 0,
CPP_SCOPE_TAKING,
CPP_SCOPE_TAKEN
} CppScope;
struct _Cpp
{
int filters;
@ -65,9 +72,12 @@ struct _Cpp
Cpp * subparser;
char ** paths;
size_t paths_cnt;
/* substitutions */
/* for substitutions */
CppDefine * defines;
size_t defines_cnt;
/* for context */
CppScope * scopes;
size_t scopes_cnt;
};
/* FIXME use CPP_CODE_META_* in a structure with strings and pointers to
@ -172,6 +182,12 @@ static char * _cpp_parse_word(Parser * parser, int c);
static int _cpp_filter_newlines(int * c, void * data);
static int _cpp_filter_trigraphs(int * c, void * data);
/* scope */
static int _cpp_scope_push(Cpp * cpp, CppScope scope);
static CppScope _cpp_scope_get(Cpp * cpp);
static void _cpp_scope_set(Cpp * cpp, CppScope scope);
static int _cpp_scope_pop(Cpp * cpp);
/* callbacks */
static int _cpp_callback_directive(Parser * parser, Token * token, int c,
void * data);
@ -248,6 +264,7 @@ static char * _cpp_parse_word(Parser * parser, int c)
}
/* filters */
/* cpp_filter_newlines */
static int _cpp_filter_newlines(int * c, void * data)
{
@ -353,9 +370,57 @@ static int _trigraphs_get(int last, int * c)
}
/* scope */
/* cpp_scope_push */
static int _cpp_scope_push(Cpp * cpp, CppScope scope)
{
CppScope * p;
if((p = realloc(cpp->scopes, sizeof(*p) * (cpp->scopes_cnt + 1)))
== NULL)
return error_set_code(1, "%s", strerror(errno));
cpp->scopes = p;
p[cpp->scopes_cnt++] = scope;
return 0;
}
/* cpp_scope_get */
static CppScope _cpp_scope_get(Cpp * cpp)
{
return (cpp->scopes_cnt == 0) ? CPP_SCOPE_TAKING
: cpp->scopes[cpp->scopes_cnt - 1];
}
/* cpp_scope_set */
static void _cpp_scope_set(Cpp * cpp, CppScope scope)
{
assert(cpp->scopes_cnt > 0);
cpp->scopes[cpp->scopes_cnt - 1] = scope;
}
/* cpp_scope_pop */
static int _cpp_scope_pop(Cpp * cpp)
{
CppScope * p;
assert(cpp->scopes_cnt > 0);
if((p = realloc(cpp->scopes, sizeof(*p) * (cpp->scopes_cnt - 1)))
== NULL)
return error_set_code(1, "%s", strerror(errno));
cpp->scopes = p;
cpp->scopes_cnt--;
return 0;
}
/* callbacks */
/* cpp_callback_whitespace */
static int _cpp_callback_whitespace(Parser * parser, Token * token, int c,
void * data)
/* TODO implement a flag to actually keep the content */
{
Cpp * cpp = data;
char * str = NULL;
@ -397,6 +462,7 @@ static int _cpp_callback_whitespace(Parser * parser, Token * token, int c,
/* cpp_callback_comment */
static int _cpp_callback_comment(Parser * parser, Token * token, int c,
void * data)
/* TODO implement a flag to actually keep the content */
{
if(c != '/')
return 1;
@ -427,11 +493,13 @@ static int _cpp_callback_comment(Parser * parser, Token * token, int c,
/* cpp_callback_directive */
/* these functions should return 0 (or -1 on errors) */
/* directives: these functions should return 0 (or -1 on errors) */
static int _directive_define(Cpp * cpp, Token * token, char const * str);
static int _directive_error(Cpp * cpp, Token * token, char const * str);
static int _directive_ifdef(Token * token, char const * str);
static int _directive_ifndef(Token * token, char const * str);
static int _directive_include(Cpp * cpp, Token * token, char const * str);
static int _directive_undef(Cpp * cpp, Token * token, char const * str);
static int _directive_unknown(Token * token, char const * str);
static int _cpp_callback_directive(Parser * parser, Token * token, int c,
void * data)
@ -473,11 +541,9 @@ static int _cpp_callback_directive(Parser * parser, Token * token, int c,
token_set_code(token, CPP_CODE_META_ELIF);
break;
case CPP_DIRECTIVE_ELSE:
/* FIXME implement */
token_set_code(token, CPP_CODE_META_ELSE);
break;
case CPP_DIRECTIVE_ENDIF:
/* FIXME implement */
token_set_code(token, CPP_CODE_META_ENDIF);
break;
case CPP_DIRECTIVE_ERROR:
@ -488,12 +554,10 @@ static int _cpp_callback_directive(Parser * parser, Token * token, int c,
token_set_code(token, CPP_CODE_META_IF);
break;
case CPP_DIRECTIVE_IFDEF:
/* FIXME implement */
token_set_code(token, CPP_CODE_META_IFDEF);
ret = _directive_ifdef(token, pos);
break;
case CPP_DIRECTIVE_IFNDEF:
/* FIXME implement */
token_set_code(token, CPP_CODE_META_IFNDEF);
ret = _directive_ifndef(token, pos);
break;
case CPP_DIRECTIVE_INCLUDE:
ret = _directive_include(cpp, token, pos);
@ -513,13 +577,25 @@ static int _cpp_callback_directive(Parser * parser, Token * token, int c,
token_set_code(token, CPP_CODE_META_WARNING);
break;
default:
_directive_error(cpp, token, str);
_directive_unknown(token, str);
break;
}
free(str);
return ret;
}
static int _directive_unknown(Token * token, char const * str)
{
char buf[256];
token_set_code(token, CPP_CODE_META_ERROR);
snprintf(buf, sizeof(buf), "%s%s", "Unknown directive: ", str);
token_set_string(token, buf);
return 0;
}
/* directives */
/* directive_define */
static int _directive_define(Cpp * cpp, Token * token, char const * str)
{
size_t i;
@ -549,25 +625,41 @@ static int _directive_define(Cpp * cpp, Token * token, char const * str)
return 0;
}
static int _directive_error(Cpp * cpp, Token * token, char const * str)
/* FIXME line and column will probably be wrong for included content
* use a parser to keep track of it? */
/* directive_ifdef */
static int _directive_ifdef(Token * token, char const * str)
{
char buf[256];
char * p;
token_set_code(token, CPP_CODE_META_ERROR);
snprintf(buf, sizeof(buf), "%s%s", "Unknown or invalid directive: ",
str);
token_set_string(token, buf);
if((p = strdup(str)) == NULL)
return -error_set_code(1, "%s", strerror(errno));
token_set_code(token, CPP_CODE_META_IFDEF);
token_set_data(token, p);
return 0;
}
/* directive_ifndef */
static int _directive_ifndef(Token * token, char const * str)
{
char * p;
if((p = strdup(str)) == NULL)
return -error_set_code(1, "%s", strerror(errno));
token_set_code(token, CPP_CODE_META_IFNDEF);
token_set_data(token, p);
return 0;
}
/* directive_include */
static char * _include_path(Cpp * cpp, Token * token, char const * str);
static char * _path_lookup(Cpp * cpp, Token * token, char const * path,
int system);
static char * _lookup_error(Token * token, char const * path, int system);
static int _directive_include(Cpp * cpp, Token * token, char const * str)
{
char * path;
size_t i;
size_t j;
if((path = _include_path(cpp, token, str)) == NULL)
return 0;
@ -581,7 +673,11 @@ static int _directive_include(Cpp * cpp, Token * token, char const * str)
for(i = 0; i < cpp->paths_cnt; i++)
if(cpp_path_add(cpp->subparser, cpp->paths[i]) != 0)
break;
if(i != cpp->paths_cnt)
for(j = 0; j < cpp->defines_cnt; j++)
if(cpp_define_add(cpp->subparser, cpp->defines[j].name,
cpp->defines[j].value) != 0)
break;
if(i != cpp->paths_cnt || j != cpp->defines_cnt)
{
cpp_delete(cpp->subparser);
cpp->subparser = NULL;
@ -590,8 +686,6 @@ static int _directive_include(Cpp * cpp, Token * token, char const * str)
return 0;
}
static char * _path_lookup(Cpp * cpp, Token * token, char const * path,
int system);
static char * _include_path(Cpp * cpp, Token * token, char const * str)
/* FIXME use presets for path discovery and then dirname(filename) */
{
@ -620,7 +714,6 @@ static char * _include_path(Cpp * cpp, Token * token, char const * str)
return p;
}
static char * _lookup_error(Token * token, char const * path, int system);
static char * _path_lookup(Cpp * cpp, Token * token, char const * path,
int system)
{
@ -661,6 +754,7 @@ static char * _lookup_error(Token * token, char const * path, int system)
return NULL;
}
/* directive_undef */
static int _directive_undef(Cpp * cpp, Token * token, char const * str)
{
cpp_define_remove(cpp, str);
@ -820,16 +914,10 @@ Cpp * cpp_new(char const * filename, int filters)
if((cpp = object_new(sizeof(*cpp))) == NULL)
return NULL;
memset(cpp, 0, sizeof(*cpp));
cpp->filters = filters;
cpp->parser = parser_new(filename);
cpp->newlines_last_cnt = 0;
cpp->trigraphs_last_cnt = 0;
cpp->directive_newline = 1;
cpp->subparser = NULL;
cpp->paths = NULL;
cpp->paths_cnt = 0;
cpp->defines = NULL;
cpp->defines_cnt = 0;
if((p = strdup(filename)) != NULL)
{
cpp_path_add(cpp, dirname(p)); /* FIXME inclusion order */
@ -862,6 +950,8 @@ void cpp_delete(Cpp * cpp)
cpp_delete(cpp->subparser);
if(cpp->parser != NULL)
parser_delete(cpp->parser);
if(cpp->scopes != NULL)
free(cpp->scopes);
object_delete(cpp);
}
@ -876,6 +966,18 @@ char const * cpp_get_filename(Cpp * cpp)
}
/* cpp_is_defined */
int cpp_is_defined(Cpp * cpp, char const * name)
{
size_t i;
for(i = 0; i < cpp->defines_cnt; i++)
if(strcmp(cpp->defines[i].name, name) == 0)
return 1;
return 0;
}
/* useful */
/* cpp_define_add */
int cpp_define_add(Cpp * cpp, char const * name, char const * value)
@ -956,11 +1058,93 @@ int cpp_path_add(Cpp * cpp, char const * path)
/* cpp_scan */
static int _scan_get_next(Cpp * cpp, Token ** token);
int cpp_scan(Cpp * cpp, Token ** token)
{
int ret;
TokenCode code;
char * name;
int take;
CppScope scope;
if((ret = _scan_get_next(cpp, token)) != 0)
return ret;
if(*token == NULL)
return 0;
if((code = token_get_code(*token)) == CPP_CODE_META_IFDEF
|| code == CPP_CODE_META_IFNDEF)
{
name = token_get_data(*token);
take = cpp_is_defined(cpp, name);
token_set_data(*token, NULL);
free(name);
take = (code == CPP_CODE_META_IFDEF) ? take : !take;
_cpp_scope_push(cpp, take ? CPP_SCOPE_TAKING
: CPP_SCOPE_NOTYET);
return 0;
}
if(code == CPP_CODE_META_IF)
{
/* FIXME check the condition */
_cpp_scope_push(cpp, CPP_SCOPE_TAKING);
return 0;
}
if(code == CPP_CODE_META_ELIF)
{
if(cpp->scopes_cnt == 0)
{
token_set_code(*token, CPP_CODE_META_ERROR);
token_set_string(*token, "#elif without #if or #ifdef"
" or #ifndef");
return 0;
}
/* FIXME check the condition */
scope = _cpp_scope_get(cpp);
if(scope == CPP_SCOPE_TAKING)
_cpp_scope_set(cpp, CPP_SCOPE_TAKEN);
else if(scope == CPP_SCOPE_NOTYET)
_cpp_scope_set(cpp, CPP_SCOPE_TAKING);
return 0;
}
if(code == CPP_CODE_META_ELSE)
{
if(cpp->scopes_cnt == 0)
{
token_set_code(*token, CPP_CODE_META_ERROR);
token_set_string(*token, "#else without #if or #ifdef"
" or #ifndef");
return 0;
}
scope = _cpp_scope_get(cpp);
if(scope == CPP_SCOPE_TAKING)
_cpp_scope_set(cpp, CPP_SCOPE_TAKEN);
else if(scope == CPP_SCOPE_NOTYET)
_cpp_scope_set(cpp, CPP_SCOPE_TAKING);
return 0;
}
if(code == CPP_CODE_META_ENDIF)
{
if(cpp->scopes_cnt == 0)
{
token_set_code(*token, CPP_CODE_META_ERROR);
token_set_string(*token, "#endif without #if or #ifdef"
" or #ifndef");
}
_cpp_scope_pop(cpp);
return 0;
}
if(_cpp_scope_get(cpp) == CPP_SCOPE_TAKING)
return 0;
token_delete(*token);
return cpp_scan(cpp, token); /* FIXME do this in a loop */
}
static int _scan_get_next(Cpp * cpp, Token ** token)
{
if(cpp->subparser != NULL)
{
if(cpp_scan(cpp->subparser, token) != 0)
if(_scan_get_next(cpp->subparser, token) != 0)
return 1;
if(*token != NULL)
return 0;