view mc-macro.c @ 343:11f8f2e6bb72

fix eof and multi-file, mc-parse else-if switch
author kono
date Sun, 27 Jun 2004 10:39:18 +0900
parents da2e3f2d127d
children 969089695850
line wrap: on
line source

/* Micro-C Preprocessor Part */ /* $Id$ */

#include <stdio.h>
#include "mc.h"
#include "mc-parse.h"
#include "mc-macro.h"
#include "mc-code.h"

extern struct {int fd,ln;char *name0;int inc;FILE *fcb;} *filep,filestack[FILES];

int in_macro_if = 0;
char *chinput;

static char *macropp,macro_buf[MACROSIZE];
static int mconcat=0;

static void macro_define0();
static int macro_args(char **pcheapp,char *maxcheap,char **pchptr);
static int macro_function(int macrop,char **pchptr,NMTBL *nptr,int history);
static void local_define(char *macro,char *value);
static void local_undef(char *macro);
static int macro_eval(int macrop,char *body0,int history);
static char * mappend(int lists);
static int macro_processing();

static void
gen_source(char *s)
{
     printf("%s",s);
}

extern void
macro_expansion(NMTBL *nptrm)
{
    int i = mode;
    int macrop = 0;
    int slfree = lfree;
    mode = STAT;

    macropp = macro_buf;
    if (nptrm->sc == FMACRO) {
        macrop=macro_function(macrop,&chptr,nptrm,0);
    } else {
        macrop=macro_eval(macrop,(char *)car(nptrm->dsp),0);
    }
    macropp = macro_buf;
    mappend(reverse0(macrop));
    macropp[-1] ='\n';
    *macropp =0;
    while (mconcat) {
        // ## re-eval macro
        printf("## %s",macro_buf);
        mconcat = 0;
        macrop = 0;
        macropp = macro_buf;
        macrop=macro_eval(macrop,macro_buf,0);
        macropp = macro_buf;
        mappend(reverse0(macrop));
        macropp[-1] ='\n';
        *macropp =0;
    }
    mconcat = 0;
    lfree = slfree;
    if (lsrc && !asmf && nptrm->sc==FMACRO) gen_comment(macro_buf);
    macropp[-1] =0;
    if (macro_buf[0]==0) {
        mode = i;
        return;
    }
    chptrsave = glist2((int)chptr,chptrsave);
    chsave = glist2(ch,chsave);
    chptr = macro_buf;
    ch = *chptr++;
    mode = i;
}

/* file inclusion */

static char *
expand_file_name(char *path,char *name,int pos,int lbufsize)
{
    char *p = name+pos;
    int i,j;
    j = 0;
    for(i=0;path[i];i++,j++); for(i=0;name[i];i++,j++);
    if (pos+j+1>lbufsize) { error(FILERR); return ""; }
    while((name[pos++] = *path++));
    pos--;
    if (name[pos]!='/') name[pos]='/';
    for(i = 0; ((name[pos++] = name[i++])););
    return p;
}

static FILE *
getfname(void)
{
    int i,end='"',err=0;
    char *s,*p,**pp,name[LBUFSIZE];
    FILE *fp;

    getch();
    if(skipspc()=='"') { end = '"';
    } else if (ch=='<') { end = '>';
    } else { error(INCERR); err=1; 
    }
    for(i=0;(getch()!=end && ch!='\n');) {
	if(i<LBUFSIZE-1) name[i++]=ch;
    }
    if(ch=='\n') error(INCERR);
    if (err) return filep->fcb;
    name[i]=0;
    fp = fopen(name,"r") ;
    if (fp) {
	p = name; 
    } else {
	for(pp=(end=='>'||filep->inc=='>')
		?l_include_path:include_path;*pp;pp++) {
	    p = expand_file_name(*pp,name,i+1,LBUFSIZE);
	    if ((fp = fopen(p,"r"))) break ;
	}
    }
    if(!fp) { error(FILERR); return filep->fcb; }
    copy_current_file_dir(s=p);
    (filep+1)->name0 = cheapp;
    (filep+1)->inc = end;
    while((*cheapp++ = *s++));
    return ( (filep+1)->fcb = fp );
}

/* line input and conversion */

static int macro_if_depth ;
static int macro_if_current ;
static int macro_if_skip ;

static int
skip_rest_of_line()
{
    getch();
    do {
	while(ch!='\n'&&ch!='\r') {
	    if (!in_comment) {
		if (ch=='/') {
		    getch();
		    if (ch=='/') in_comment=2;
		    else if (ch=='*') {
			in_comment=1;
		    } else continue;
		}
	    } else if (ch=='*') {
		getch();
		if (ch=='/') {
		    in_comment=0; 
		    return macro_if_skip?0:1;
		}
		else continue;
	    }
	    getch();
	}
	if (in_comment==1) { getline(); getch(); }
    } while(in_comment==1);
    in_comment=0;
    return 0;
}

static int next_eof;

extern void
getline(void)
{
    int i;
    int c;

    if (next_eof) {
	next_eof=0;
	error(EOFERR);
    }
    do {
	if (chinput) {
	    if (! *chinput) {
		chinput=0;
		continue;
	    }
	    chptr=linebuf;
	    i=0;
	    while((*chptr++=c=*chinput++)&&(c!='\n')) {
		if (++i > LBUFSIZE-2) error(LNERR);
	    }
	} else {
	    lineno++;
	    glineno++;
	    chptr=linebuf;
	    i=0;
	    while ((*chptr++ = c = getc(filep->fcb)) != '\n') {
		if (++i > LBUFSIZE-2) error(LNERR);
		if (c==EOF) {
		    next_eof=1;
		    --chptr;
		    break;
		}
	    }
	}
	*chptr = '\0';
	if (lsrc && !asmf && !macro_if_skip && linebuf[0]) gen_comment(linebuf);
	if (*(chptr = linebuf) == '#' && !in_comment && !in_quote) {
	    if (macro_processing()) return;
	}
    } while(!in_quote && (macro_if_skip || linebuf[0] == '#'));
}

/* preprocessor directive */

/* line continuation \\ */

extern void
check_macro_eof()
{
    int c;
    for(c=0;c<LBUFSIZE-3&&chptr[c];c++);
    if (c>0&&chptr[c-1]=='\\') {
	return;
    } else if (c>0&&chptr[c-1]=='\n') {
	if (c>0&&chptr[c-2]=='\\') {
	    return;
	} else {
	    c--;
	}
    } 
    chptr[c] = ';';
    chptr[c+1] = '\n';
    chptr[c+2] = 0;
}

static void
macro_if()
{
    int i;
    ch= *chptr;
    in_macro_if = 1;
    check_macro_eof();
    getsym(0);
    /* i=cexpr(expr(1)); #if allow undefined symbols.. */
    i=expr(1); 
    in_macro_if = 0;
    if (car(i)==CONST) i=cadr(i);
    else i=0;
    if (ch) {
	if (chptr[-1]==ch) {
	/* we are fall into getch(), which lost the last ch */
	/* chptr[-1]==ch check is fanatic, but ... */
	    chptr--;
	} else error(-1);
    }
    macro_if_depth = macro_if_current;
    macro_if_skip = !i;
}

static int
macro_processing()
{
    int i;
    int c;
    int mode_save;

    ++chptr;
    while (*chptr==' '||*chptr=='\t') ++chptr;
    if (macroeq("ifdef") || macroeq("ifndef")) {
	c = (chptr[-4]=='n');
	macro_if_current++;
	if (!macro_if_skip) {
	    mode_save = mode; mode = IFDEF;
	    ch= *chptr;
	    i = getsym(0);
	    mode = mode_save;
	    macro_if_depth = macro_if_current;
	    macro_if_skip = (!i)^c;
	}
	return 0;
    } else if (macroeq("elif")) {
	if (macro_if_current==0) {
	    error(MCERR); /* extra #else */
	    return 0;
	}
	if (macro_if_current == macro_if_depth) {
	    if (!macro_if_skip || macro_if_skip==2) {
		macro_if_skip=2;
		return 0;
	    }
	    macro_if();
	}
	return 0;
    } else if (macroeq("if")) {
	macro_if_current++;
	if (!macro_if_skip) {
	    macro_if();
	}
	return 0;
    } else if (macroeq("else")) {
	if (macro_if_current==0) {
	    error(MCERR); /* extra #else */
	    return 0;
	}
	if (macro_if_current == macro_if_depth) {
	    if (macro_if_skip==2) ;
	    else if (macro_if_skip) macro_if_skip=0;
	    else macro_if_skip=1;
	}
	return skip_rest_of_line();
    } else if (macroeq("endif")) {
	if (macro_if_current == macro_if_depth) {
	    macro_if_skip = 0;
	    macro_if_depth = --macro_if_current;
	} else {
	    if (macro_if_current<=0) {
		error(MCERR); /* extra #if */
		return 0;
	    }
	    macro_if_current--;
	}
	return skip_rest_of_line();
    }
    if (macro_if_skip) return 0;
    if (macroeq("define")) {
	ch= *chptr;
	macro_define0();
	*(chptr = linebuf) = '\0';
    } else if (macroeq("undef")) {
	i=mode;
	mode=IFDEF;
	ch= *chptr;
	if (getsym(0)) {
	    if (nptr->sc == MACRO) {
	        nptr->sc = EMPTY;
	    } else if (nptr->sc == FMACRO) {
	        nptr->sc = EMPTY;
		/* we cannot reclaim it's arg */
	    } else error(MCERR);
	}
	mode=i;
    } else if (macroeq("include")) {
	if(filep+1 >= filestack + FILES) error(FILERR);
	if ( ((filep+1)->fcb=getfname()) == NULL) error(FILERR);
	(filep+1)->ln=lineno;
	lineno=0;
	++filep;
	*(chptr = linebuf) = '\0';
#if ASM_CODE
    } else if (macroeq("asm")) {
	if (asmf) error(MCERR);
	asmf = 1;
	getline();
	while (asmf) {
	    gen_source(linebuf);
	    getline();
	}
    } else if (macroeq("endasm")) {
	if (!asmf) error(MCERR);
	asmf = 0;
#endif
    } else if (macroeq(" "))
	getline();
    else error(MCERR);
    return 0;
}

extern int
macroeq(char *s)
{
    char *p;

    for (p = chptr; *s;) if (*s++ != *p++) return 0;
    chptr = p;
    return 1;
}

/* macro interpreter */

extern void
macro_define(char *macro)
{
    char *chptr_save;
    int chsave;

    chptr_save = chptr;
    chsave = ch;
    chptr = macro;
    ch= *chptr++;
    macro_define0();
    chptr = chptr_save;
    ch = chsave;
}

static void
macro_define0()
{
    int i,args,c;
    char *scheapp;

    i=mode;
    mode=MDECL;
    // ch= *chptr; ??
// fprintf(stderr,"macro def: ch %c *chptr %c\n",ch,*chptr);
    getsym(0);
// fprintf(stderr,"macro def: %s =>",name); 
    if (nptr->sc != EMPTY) { /* override existing macro */
    }
    args = 0;
    if (ch=='(') {
	nptr->sc = FMACRO;
	args = macro_args(&cheapp,cheap+CHEAPSIZE,&chptr);
    } else {
	nptr->sc = MACRO;
	nptr->ty = -1;
    }
    // equal is allowed for -Dhoge=aho option
    if (ch=='=') chptr++;
    while((c=*chptr)==' '||c=='\t') chptr++;
    nptr->dsp = list2((int)cheapp,args); /* macro body */
    scheapp = cheapp;
    while ((*cheapp++ = c = *chptr++)
	&& c != '\n') {
	if (c=='/'&&chptr[0]=='/') {
	    cheapp--; while(*chptr++); break;
	} else if (c=='/'&&chptr[0]=='*') {
	    cheapp--; chptr++;
	    while((c = *chptr++)) {
		if (c=='*'&&chptr[0]=='/') {
		    c = *chptr++; break;
		}
	    }
	    if (!c) break;
	} else if (c=='\\' && (*chptr=='\n'||*chptr==0)) {
	    chptr++;
	    cheapp--;
	    getline();
	}
    }
    *cheapp++ = '\0';
    while(cheapp>scheapp&&(*cheapp=='\n'||*cheapp==0)) cheapp--;
    *++cheapp = '\0'; cheapp++;
    if (cheapp >= cheap+CHEAPSIZE) /* too late? */
	error(STRERR);
// fprintf(stderr,"%s\n",(char *)car(nptr->dsp));
    mode=i;
}

// create function macro argument list
//    return  list2((char*)arg,next)

static int
macro_args(char **pcheapp,char *maxcheap,char **pchptr)
{
    int c;
    int in_quote = 0;
    int in_wquote = 0;
    int plevel = 0;
    char *cheapp = *pcheapp;
    char *chptr = *pchptr;
    int args = list2((int)cheapp,0);
    for(;;) {
        *cheapp++ = c = *chptr++;
	if (cheapp >= maxcheap) error(MCERR);
	if (!c)  {
	    chptr--;
	    error(MCERR);
	    *pchptr = chptr;
	    *pcheapp = cheapp;
	    return reverse0(args);
	}
	if (in_quote) {
	    if (c=='\\') {
		if (*chptr != '\n') {
		    *cheapp++ = *chptr++;
		} else {
		    getline();
		}
	    } else if (c=='\'') {
		in_quote = 0;
	    }
	} else if (in_wquote) {
	    if (c=='\\') {
		if (*chptr !='\n') {
		    *cheapp++ = *chptr++;
		} else {
		    *cheapp = '\n';
		    getline();
		}
	    } else if (c=='"') {
		in_wquote = 0;
	    }
	} else if (c=='"') {
	    in_wquote = 1;
	} else if (c=='\'') {
	    in_quote = 1;
	} if (plevel==0) {
	    if (c==',') {
		cheapp[-1] = 0;
		args = list2((int)cheapp,args);
	    } else if (c==')') {
		cheapp[-1] = 0;
		break;
	    } else if (c=='(') {
		plevel++;
	    } else if (c=='\\') {
		if (*chptr=='\n') {
		    cheapp--;
		    getline();
		}
//	    } else if (c==' '||c=='\t') {
//		cheapp--;
	    } else if (c=='\n') {
		cheapp--;
		getline();
		chptr = *pchptr;
	    }
	} else if (c==')') {
	    plevel--;
	} else if (c=='(') {
	    plevel++;
	} else if (c=='\n') {
	    cheapp--;
	    getline();
	    chptr = *pchptr;
	}
    }
    *pchptr = chptr;
    *pcheapp = cheapp;
    return reverse0(args);
}

/* output macro expansion result into macrobuf (macropp) */

static int
macro_function(int macrop,char **pchptr,NMTBL *nptr,int history)
{
    int args,sargs,values,evalues;
    char *macro;

    sargs = args = cadr(nptr->dsp);
    values = macro_args(&macropp,macro_buf+MACROSIZE,pchptr);
    if (pchptr==&chptr) {
	ch = *chptr++;
    }
    evalues = 0;
    while(values) {
	evalues = list2(macro_eval(0,(char *)car(values),history),evalues);
	values = cadr(values);
    }
    evalues = reverse0(evalues);
    while(args) {
	local_define((char *)car(args),mappend(reverse0(car(evalues))));
/* fprintf(stderr,"%s: %s => %s\n",nptr->nm,(char *)car(args),(char *)car(msearch0((char *)car(args))->dsp)); */
	args = cadr(args);
	evalues = cadr(evalues);
    }
    macro = (char *)car(nptr->dsp);
    macrop = macro_eval(macrop,macro,list2((int)macro,history));
/* fprintf(stderr,"%s: result %s => %s\n",nptr->nm,macro,(char *)car(macrop)); */
    args = sargs;
    while(args) {
	local_undef((char *)car(args));
	args = cadr(args);
    }
    return macrop;
}

static void
local_define(char *macro,char *value)
{
    NMTBL *nptr0;
    while(*macro==' '||*macro=='\t') macro++;
    nptr0 = msearch0(macro);
    /* save nptr previous contents in a list */
    nptr0->ty=list3(nptr0->sc,nptr0->ty,nptr0->dsp);
    /* set new value */
    nptr0->sc=LMACRO;
    nptr0->dsp=list2((int)value,0);
}

static void
local_undef(char *macro)
{
    NMTBL *nptr0;
    int save;
    nptr0 = msearch0(macro);
    save = nptr0->ty;
    nptr0->sc=car(save);
    nptr0->dsp=caddr(save);
    nptr0->ty=cadr(save);
}

static int
macro_eval(int macrop,char *body0,int history)
{
    int c;
    int in_quote = 0;
    int in_wquote = 0;
    char *macro;
    char *body = body0;
    int i;
    NMTBL *nptrm;
    macrop = list2((int)macropp,macrop);
    for(; (c = *body++) ;) {
	if (macropp+1>macro_buf+MACROSIZE) error(STRERR);
	if (in_quote) {
	    if (c=='\\') {
		*macropp++ = c; c = *body++;
	    } else if (c=='\'') {
		in_quote = 0;
	    }
	} else if (in_wquote) {
	    if (c=='\\') {
		*macropp++ = c; c = *body++;
	    } else if (c=='"') {
		in_wquote = 0;
	    }
	} else if (c=='"') {
	    in_wquote = 1;
	} else if (c=='\'') {
	    in_quote = 1;
	} else if (c=='#' && *body=='#') {
	    // name concatenation. skip ## and re-eval macro line.
	    mconcat = 1; body++; continue;
	} else if (alpha(c)) {
	    i = 0;
	    do { namebuf[i++] = c; c=*body++;} while (alpha(c)||digit(c));
	    body--; // ungetc
	    namebuf[i]=0;
	    nptrm = msearch0(namebuf);
	    macro = (char *)car(nptrm->dsp);
	    if (nptrm->sc==LMACRO) {
		while((*macropp++ = *macro++));
		macropp--;
	    } else if (nptrm->sc==MACRO && neqname(namebuf,macro)) {
		if (macro[0]==0)  continue;
		*macropp++=0;
                macrop=macro_eval(macrop,macro,list2((int)macro,history));
		macrop = list2((int)macropp,macrop);
	    } else if (nptrm->sc==FMACRO) {
		if (c==' '||c=='\t') {
		    while (c==' '||c=='\t') c=*body++;
		    body--;
		}
		if(c!='(') error(MCERR);
		*macropp++=0; body++;
		macrop = macro_function(macrop,&body,nptrm,
			list2((int)macro,history));
		macrop = list2((int)macropp,macrop);
	    } else {
		macro = namebuf;
		while((*macropp++ = *macro++));
		macropp--;
	    }
	    continue;
	}
	*macropp++ = c;
    }
    *macropp++=0;
    return macrop;
}


static char *
mappend(int lists)
{
    char *p;
    char *result = macropp;
    while(lists) {
        if (macropp>macro_buf+MACROSIZE) error(STRERR);
        p = (char *)car(lists);
        while((*macropp++=*p++)) if (p[-1]=='\n') macropp[-1]=' ';
        macropp--;
        lists = cadr(lists);
    }
    macropp++;
    return result;
}

/* end */