📄 preproc.c
字号:
/* preproc.c
*
* (C) Copyright Apr 15 1995, Edmond J. Breen.
* ALL RIGHTS RESERVED.
* This code may be copied for personal, non-profit use only.
*
* Developed initially from
* p -- Small-C preprocessor by A.T. Schreiner 6/83.
* DDJ #93 (July) 1984.
*
* However, many changes have been implemented and
* extensions made.
*
* Grammar
* #define identifier token-sequence
* #define identifier(arg-list) token-sequence
* #undef identifier
* #include <file-name>
* #include "file-name"
* #include token-sequence
* #if constant-expr
* #elif constant-expr
* #ifdef identifier
* #ifndef identifier
* #else
* #endif
* #error token-sequence
# #pragma token-sequence
# #pragma
*
* The defined operator can be used in #if and #elif
* expressions only:
* #if defined(_EiC) && !defined(UNIX)
* ...
* #elif defined(MSDOS)
* ...
* #endif
*
* token-sequence:
* [token-sequence] #token [token-sequence]
* [token-sequence] token##token [token-sequence]
* token-sequence token
*
* arg-list:
* identifier [,identifier]*
*
* Predefined Macros:
*
* __LINE__ The line number of the current source program, expressed
* as an integer.
* __FILE__ The name of the current source file, expressed as a
* string.
* __DATE__ resolves to a string literal containing the calender
* date in the form: Mmm dd yyyy.
* __TIME__ resolves to a string literal containing the current time
* in the form hh:mm:ss.
* __STDC__ resolves to 1.
*
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <stddef.h>
#include <stdarg.h>
#include "stab.h"
#include "error.h"
#include "func.h"
#ifdef PPCLIB
int _stsptr,persist;
char *startstr;
char *ppcgets(char *str);
#endif
#ifdef _STANDALONE
#include "preproc.h"
int EiC_verboseON=1;
int showON = 1;
#define xmalloc(x) malloc(x)
#define xcalloc(x,y) calloc(x,y)
#define xrealloc(x,y) realloc(x,y)
#define xfree(x) free(x)
#define xmark(x,y)
union VaL {
char cval; /* char value */
int ival; /* integer value */
char *cpval;
void *pval;
};
typedef union VaL val_t;
typedef struct {
int n;
val_t * val;
}eicstack_t;
typedef struct {
char *id;
int token;
} keyword_t;
#include "preexpr.c"
#else
static int showON = 0;
#include "global.h"
#include "xalloc.h"
#include "preproc.h"
#include "symbol.h"
#endif
/* TODO: constant from eicmod.c needs header */
extern int EiC_showIncludes;
fitem_t *EiC_Infile = NULL;
int EiC_ptrSafe = 1;
static int file_cnt = 0;
static stab_t FileNames = {NULL,0};
#define crt_fitem() (fitem_t*)calloc(sizeof(fitem_t),1)
#define free_fitem(x) free(x)
#define STRINGID -2
int EiC_IsIncluded(char *fname)
{
return EiC_stab_FindString(&FileNames,fname) >= 0;
}
void EiC_showIncludedFiles(void)
{
EiC_stab_ShowStrings(&FileNames);
}
void EiC_rmIncludeFileName(char *fname)
{
EiC_stab_RemoveString(&FileNames,fname);
}
#if 0
/* this is the start of getting the :clear
* command to recursively remove the contents
* of an include file
*/
typedef struct nameTab {
char * fname;
char * inc;
struct nameTab *nxt;
};
static struct nameTab *incTab = NULL;
static void EiC_addIncAssoc(char *fname, char *inc)
{
struct nameTab *new = xcalloc(sizeof(new), 1);
new->fname = fname;
new->inc = inc;
new->nxt = incTab;
incTab = new;
}
#endif
static void NewInfile(int fd, char * fname, char *filep)
{
fitem_t * f = crt_fitem();
f->fd = fd;
f->fname = EiC_stab_SaveString(&FileNames,fname);
f->next = EiC_Infile;
EiC_Infile = f;
if(EiC_showIncludes) {
int k = file_cnt;
while(--k)
fputs(" ",stdout);
if((filep && !*filep) || !filep)
filep = fname;
fprintf(stdout,"%d:%s\n",file_cnt,filep);
}
file_cnt++;
}
static void NextInfile()
{
if(EiC_Infile->next) {
fitem_t * h = EiC_Infile->next;
if(EiC_Infile->fd != STRINGID) {
close(EiC_Infile->fd);
if(EiC_Infile->buf)
free(EiC_Infile->buf);
}
free(EiC_Infile);
EiC_Infile = h;
file_cnt--;
}
}
static eicstack_t macros = {0, NULL};
#define Item(stack,i,item) ((stack)->val[i].item)
#define STDIN 0
#define STDOUT 1
#define STDERR 2
typedef struct {
char * line;
char * lp;
unsigned len;
}Line;
static size_t NINCLUDES = 0;
static char **Include_prefixes = NULL;
static char *empty_string = " ";
typedef struct {
char *id; /* token name */
char *tok_seq; /* token replacement sequence */
int nparms; /* number of parameters */
char *protect; /* if one then no expansion before
replacement for a given parameter*/
long unsigned hcode; /* `id' string hash code */
char *fname; /* file name pointer */
} macro_t;
static macro_t defmacro = {NULL, NULL, 0, NULL};
static int skip = 0;
char cmode;
static int linelen, olinelen, iflevel =0;
static char *line = NULL, *lp, *oline = NULL, *olp;
enum {
DEFAULT, DEFINE,
ELIF, ELSE, ENDIF,
IF, IFDEF, IFNDEF, INCLUDE,
UNDEF, ERROR, PRAGMA
};
static keyword_t pwords[] =
{
{"define", DEFINE,},
{"elif", ELIF,},
{"else", ELSE,},
{"endif",ENDIF,},
{"error", ERROR,},
{"if", IF,},
{"ifdef", IFDEF,},
{"ifndef",IFNDEF,},
{"include",INCLUDE,},
{"pragma", PRAGMA,},
{"undef", UNDEF,},
};
/** PROTOTYPES from preproc.c **/
static int Rgetc();
static void rebuff(char **buf, int *len);
static void in(char c);
static char *out(char c);
static char *outChar(char *s, char c, int mod, int i);
static int getline();
static void expr_list(eicstack_t *parms, char **p,int more);
static int findparm(eicstack_t *parms,char *name, size_t len);
static void mergeTokens(macro_t *mac);
static void parameterise(eicstack_t *parms);
static void markmacro(macro_t * mac, char mark);
static void kill_Items(eicstack_t *parms);
static void freemacro(macro_t * mac);
static void remmacroid(int k);
static void newmacro(eicstack_t *parms);
static void dodefmacro(char *s);
static int control_line(void);
static char * stringise(char * seq);
static char * EiC_expand(char *fld,char **end, int bot, int top);
static void process(void);
/* TODO: extern from eicmod.c needs header */
extern int EiC_verboseON;
static unsigned long get_hcode(unsigned char *s)
{
unsigned long t, h,i;
h = 0;
while(*s) {
for(t = i=0;*s && i<32;i+=8)
t |= (*s++ << i);
h += t;
}
return h;
}
/*CUT preprocerror.cut*/
extern void EiC_pre_error(char *msg, ...)
{
char *buff1, *buff2;
va_list args;
va_start(args,msg);
buff1 = malloc(strlen(msg) + 256);
buff2 = malloc(strlen(msg) + 512);
EiC_errs++;
EiC_ParseError = 1;
sprintf(buff1,"Error in %s near line %d: %s\n",
CurrentFileName(),
CurrentLineNo(),
msg);
vsprintf(buff2,buff1,args);
EiC_messageDisplay(buff2);
free(buff1);
free(buff2);
va_end(args);
}
/*END CUT*/
static size_t ninclude = 0;
static size_t bot_stab = 0;
size_t EiC_pp_NextEntryNum(void)
{
ninclude = NINCLUDES;
bot_stab = EiC_stab_NextEntryNum(&FileNames);
return macros.n;
}
size_t EiC_get_EiC_PP_NINCLUDES(void){ return NINCLUDES;}
size_t EiC_get_EiC_bot_stab(void) {return EiC_stab_NextEntryNum(&FileNames);}
void EiC_set_EiC_PPtoStart(int bot_stab, int ninclude)
{
NINCLUDES = ninclude;
FileNames.n = bot_stab;
}
void EiC_pp_CleanUp(size_t bot)
{
iflevel = 0;
skip = 0;
/* clean up macros */
while(macros.n > bot)
remmacroid(macros.n-1);
/* close opened files */
while(EiC_Infile->next)
NextInfile();
/* clean up path inclusion */
while(NINCLUDES > ninclude)
EiC_removepath(Include_prefixes[NINCLUDES - 1]);
/* remove included file names */
EiC_stab_CleanUp(&FileNames,bot_stab);
}
static unsigned putback = 0;
#define Ugetc(x) (putback = x)
#define BUFSIZE 512
#if 1
static void doPragma(char *s)
{
static char * Stack = NULL;
static int N = 0;
if(strstr(s,"push_safeptr")) {
Stack = realloc(Stack,++N);
Stack[N-1] = EiC_ptrSafe = 1;
} else if(strstr(s,"push_unsafeptr")) {
Stack = realloc(Stack,++N);
Stack[N-1] = EiC_ptrSafe = 0;
} else if(strstr(s,"pop_ptr") ) {
if(N-2 >= 0) {
N--;
EiC_ptrSafe = Stack[N-1];
} else
EiC_ptrSafe = 1;
} else
EiC_formatMessage("Warning: Unrecognised pragma (%s): %s line %d\n",
s,EiC_Infile->fname, EiC_Infile->lineno);
}
#endif
#if defined(_STANDALONE)
#define gchar(fd,c) (c = (read(fd,&c,1) > 0)? c : EOF)
static int rline(int fd, char *s, int limit)
{
int c =0, i;
limit--;
for(i=0;i<limit && gchar(fd,c) != EOF && c != '\n';i++)
s[i] = c;
if(c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
static int Rgetc()
{
int c;
static int lastln = 0;
if(putback) {
c = putback;
putback = 0;
} else {
if(EiC_Infile->n <= 0) {
if(showON && lastln && !skip && EiC_Infile->buf)
fputs(EiC_Infile->buf,stdout);
EiC_Infile->n = 0;
if(EiC_Infile->buf == NULL)
EiC_Infile->buf = (char *)malloc(BUFSIZE+1);
EiC_Infile->n = rline(EiC_Infile->fd,
EiC_Infile->buf,
BUFSIZE);
EiC_Infile->bufp = EiC_Infile->buf;
if(showON) {
lastln = 0;
if(!skip)
fprintf(stdout,"%s",EiC_Infile->buf);
else {
lastln = 1;
putchar('\n');
}
}
}
c = ((EiC_Infile->n-- > 0) ? *EiC_Infile->bufp++ : EOF);
}
return c;
}
#else
/* TODO: global from starteic.c needs header */
extern int EiC_Interact;
static int Rgetc()
{
static char prompt[20];
unsigned char * EiC_readline(char *);
void EiC_add_history(unsigned char *);
int c;
#ifdef PPCLIB
void prs(char *str);
static char getsbuf[120];
#endif
#ifdef WIN32
#define SBUFSIZE 120
static char getsbuf[SBUFSIZE];
#endif
if(putback) {
c = putback;
putback = 0;
} else {
if(EiC_Infile->n <= 0) {
if(EiC_Infile->fd != STDIN || !EiC_Interact) {
if(EiC_Infile->buf == NULL)
EiC_Infile->buf = malloc(BUFSIZE+1);
if(EiC_Infile->fd != STRINGID)
EiC_Infile->n = read(EiC_Infile->fd,
EiC_Infile->buf,BUFSIZE);
} else {
#ifdef NO_READLINE
fflush(stdout);
fflush(stderr);
sprintf(prompt,"\nEiC %d> ",EiC_Infile->lineno+1);
#ifdef PPCLIB
prs(prompt);
if(_stsptr!=-1)
{
EiC_Infile->buf=startstr;
_stsptr=-1;
}
else
#endif
EiC_Infile->buf = ppcgets(getsbuf);
if(EiC_Infile->buf && *EiC_Infile->buf) {
EiC_Infile->n = strlen(EiC_Infile->buf);
EiC_Infile->buf[EiC_Infile->n] = '\n';
EiC_Infile->n++;
} else
EiC_Infile->n = 0;
#else
if(EiC_Infile->buf) {
free(EiC_Infile->buf);
EiC_Infile->buf = NULL;
}
sprintf(prompt,"EiC %d> ",EiC_Infile->lineno+1);
EiC_Infile->buf = EiC_readline(prompt);
if(EiC_Infile->buf && *EiC_Infile->buf) {
EiC_add_history(EiC_Infile->buf);
EiC_Infile->n = strlen((char*)EiC_Infile->buf);
EiC_Infile->buf[EiC_Infile->n] = '\n';
EiC_Infile->n++;
} else
EiC_Infile->n = 0;
#endif
}
EiC_Infile->bufp = EiC_Infile->buf;
}
c = ((EiC_Infile->n-- > 0) ? *EiC_Infile->bufp++ : EOF);
}
return c;
}
#endif /* _STANDALONE */
char *EiC_prolineString(char *str)
{
NewInfile(STRINGID,"STRING","::EiC::");
EiC_Infile->n = strlen(str);
EiC_Infile->buf=EiC_Infile->bufp=(unsigned char*)str;
return str;
}
static void rebuff(char **buf, int *len)
{
*buf = (char *) realloc(*buf, (*len + REBUFF_INCREMENT) * sizeof(char));
*len += REBUFF_INCREMENT;
}
static void in(char c)
{
*lp++ = c;
if (lp >= line + linelen) {
ptrdiff_t d;
d = lp - line;
rebuff(&line, &linelen);
lp = line + (size_t) d;
}
}
static char *out(char c)
{
*olp++ = c;
if (olp >= oline + olinelen) {
ptrdiff_t d;
d = olp - oline;
rebuff(&oline, &olinelen);
olp = oline + (size_t) d;
}
*olp = '\0';
return olp - 1;
}
static char *outChar(char *s, char c, int mod, int i)
{
if(!(i%mod)) {
if(!s)
s = (char *)xmalloc(sizeof(char)*(i+mod + 1));
else
s = (char *)xrealloc(s,sizeof(char)*(i+mod + 1));
}
s[i] = c;
return s;
}
#ifdef _STANDALONE
#define EiC_saveComment() NULL
#endif
static int getline()
{
/* automatically strips out comments and
* performs line splicing.
*/
char c;
int lcom = 0;
lp = line;
while(1) {
switch ((c = Rgetc())) {
case '\\': /* look for line continuation */
switch ((c = Rgetc())) {
case EOF:
EiC_pre_error("Unexpected end of file");
case '\n':
++EiC_Infile->lineno;
continue;
case '\r': /* ignore carriage returns */
if((c = Rgetc()) == '\n') {
++EiC_Infile->lineno;
continue;
}
}
in('\\');
default:
if(!isspace(c) || lp != line) /* skip leading white */
in(c); /* space */
continue;
case EOF:
if(iflevel && file_cnt == 2)
EiC_pre_error("unterminated `#if' conditional");
++EiC_Infile->lineno;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -